{
 "cells": [
  {
   "cell_type": "code",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "JHSdxPJuN4x7",
    "outputId": "a74dc274-dd24-4415-a3e4-1fcff4e437a2",
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.574125Z",
     "start_time": "2025-02-06T01:49:36.203601Z"
    }
   },
   "source": [
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "from tqdm.auto import tqdm\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "print(sys.version_info)\n",
    "for module in mpl, np, pd, sklearn, torch:\n",
    "    print(module.__name__, module.__version__)\n",
    "\n",
    "device = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
    "print(device)\n",
    "\n",
    "seed = 42\n",
    "torch.manual_seed(seed)\n",
    "torch.cuda.manual_seed_all(seed)\n",
    "np.random.seed(seed)\n"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sys.version_info(major=3, minor=12, micro=3, releaselevel='final', serial=0)\n",
      "matplotlib 3.10.0\n",
      "numpy 1.26.4\n",
      "pandas 2.2.3\n",
      "sklearn 1.6.0\n",
      "torch 2.5.1+cpu\n",
      "cpu\n"
     ]
    }
   ],
   "execution_count": 1
  },
  {
   "cell_type": "code",
   "source": [
    "#挂载谷歌云盘\n",
    "\n",
    "# from google.colab import drive\n",
    "# drive.mount('/content/drive')"
   ],
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "yQQEArYqWylq",
    "outputId": "bc80eeee-442a-4ff2-f69e-348314f84bce",
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.577108Z",
     "start_time": "2025-02-06T01:49:50.574125Z"
    }
   },
   "outputs": [],
   "execution_count": 2
  },
  {
   "cell_type": "code",
   "source": [
    "# !cp /content/drive/MyDrive/transformer-de-en/* . -r"
   ],
   "metadata": {
    "id": "wzS4AimwWz7f",
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.580504Z",
     "start_time": "2025-02-06T01:49:50.578113Z"
    }
   },
   "outputs": [],
   "execution_count": 3
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "55aNBForN4x9"
   },
   "source": [
    "## 数据加载\n",
    "\n",
    "- 采用WMT16的德语和英语平行语料库，数据集主页：[WMT16](https://www.statmt.org/wmt16/multimodal-task.html#task1)"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "SkjBEbr1N4x-",
    "outputId": "4b9817d0-616b-41a0-ceb7-9ff6bf0f42a1",
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.583796Z",
     "start_time": "2025-02-06T01:49:50.581509Z"
    }
   },
   "source": [
    "#和jieba分词类似\n",
    "# !pip install sacremoses\n",
    "# !pip install subword-nmt\n",
    "# # BPE分词\n"
   ],
   "outputs": [],
   "execution_count": 4
  },
  {
   "cell_type": "code",
   "source": "# !sh data_multi30k.sh wmt16 wmt16_cut de en",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "Tc8aCQX-XrGv",
    "outputId": "67964082-2737-4d47-dd66-455e4ae69660",
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.587399Z",
     "start_time": "2025-02-06T01:49:50.585083Z"
    }
   },
   "outputs": [],
   "execution_count": 5
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Lvk4q0-1N4x-"
   },
   "source": [
    "Dataset"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "zCXKEwspN4x_",
    "outputId": "3dcce6fa-932f-4b22-9dc8-398a4b402733",
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.622578Z",
     "start_time": "2025-02-06T01:49:50.587399Z"
    }
   },
   "source": [
    "from pathlib import Path\n",
    "from torch.utils.data import Dataset, DataLoader\n",
    "\n",
    "\n",
    "\n",
    "class LangPairDataset(Dataset):\n",
    "\n",
    "    def __init__(\n",
    "        self, mode=\"train\", max_length=128, overwrite_cache=False, data_dir=\"wmt16\",\n",
    "    ):\n",
    "        self.data_dir = Path(data_dir)\n",
    "        cache_path = self.data_dir / \".cache\" / f\"de2en_{mode}_{max_length}.npy\"\n",
    "\n",
    "        if overwrite_cache or not cache_path.exists():\n",
    "            cache_path.parent.mkdir(parents=True, exist_ok=True) # 创建缓存目录\n",
    "\n",
    "            with open(self.data_dir / f\"{mode}_src.bpe\", \"r\", encoding=\"utf8\") as file:\n",
    "                self.src = file.readlines() # 读取源语言文件所有行\n",
    "\n",
    "            with open(self.data_dir / f\"{mode}_trg.bpe\", \"r\", encoding=\"utf8\") as file:\n",
    "                self.trg = file.readlines() # 读取目标语言文件所有行\n",
    "\n",
    "            filtered_src = []\n",
    "            filtered_trg = []\n",
    "            # max length filter,超出最大长度的句子舍弃\n",
    "            for src, trg in zip(self.src, self.trg):\n",
    "                if len(src) <= max_length and len(trg) <= max_length: # 过滤长度超过最大长度的句子\n",
    "                    filtered_src.append(src.strip()) # 去掉句子前后的空格\n",
    "                    filtered_trg.append(trg.strip())\n",
    "            filtered_src = np.array(filtered_src)\n",
    "            filtered_trg = np.array(filtered_trg)\n",
    "            np.save(\n",
    "                cache_path,\n",
    "                {\"src\": filtered_src, \"trg\": filtered_trg },\n",
    "                allow_pickle=True,\n",
    "            )#allow_pickle=True允许保存对象数组，将过滤后的数据保存为 NumPy 数组，存储在缓存文件中\n",
    "            print(f\"save cache to {cache_path}\")\n",
    "\n",
    "        else:\n",
    "            cache_dict = np.load(cache_path, allow_pickle=True).item() #allow_pickle=True允许保存对象数组\n",
    "            print(f\"load {mode} dataset from {cache_path}\")\n",
    "            filtered_src = cache_dict[\"src\"]\n",
    "            filtered_trg = cache_dict[\"trg\"]\n",
    "\n",
    "        self.src = filtered_src\n",
    "        self.trg = filtered_trg\n",
    "\n",
    "    def __getitem__(self, index):\n",
    "        return self.src[index], self.trg[index]\n",
    "\n",
    "    def __len__(self):\n",
    "        return len(self.src)\n",
    "\n",
    "\n",
    "train_ds = LangPairDataset(\"train\")\n",
    "val_ds = LangPairDataset(\"val\")"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "load train dataset from wmt16\\.cache\\de2en_train_128.npy\n",
      "load val dataset from wmt16\\.cache\\de2en_val_128.npy\n"
     ]
    }
   ],
   "execution_count": 6
  },
  {
   "cell_type": "code",
   "source": [
    "# !rm wmt16/.cache -r"
   ],
   "metadata": {
    "id": "yHB9TDpDQlv2",
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.625062Z",
     "start_time": "2025-02-06T01:49:50.622578Z"
    }
   },
   "outputs": [],
   "execution_count": 7
  },
  {
   "cell_type": "code",
   "source": [
    "len(train_ds) #少了1000多个样本"
   ],
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "meHHXL3MN4x_",
    "outputId": "a001c071-7021-4dff-8bc0-3e5da01d7210",
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.628422Z",
     "start_time": "2025-02-06T01:49:50.625062Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "27962"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 8
  },
  {
   "cell_type": "code",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "LZvJV37NN4x_",
    "outputId": "43909dbd-cf15-447b-e8b6-a07de381ad0a",
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.631146Z",
     "start_time": "2025-02-06T01:49:50.628422Z"
    }
   },
   "source": [
    "print(\"source: {}\\ntarget: {}\".format(*train_ds[-1]))"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "source: ein älterer mann sitzt mit einem jungen mit einem wagen vor einer fassade .\n",
      "target: an elderly man sits outside a storefront accompanied by a young boy with a cart .\n"
     ]
    }
   ],
   "execution_count": 9
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "TE8gRzYQN4yA"
   },
   "source": [
    "### Tokenizer\n",
    "\n",
    "这里有两种处理方式，分别对应着 encoder 和 decoder 的 word embedding 是否共享，这里实现共享的方案"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 66,
     "referenced_widgets": [
      "7190c928edb040c3a523cdd2e3f45572",
      "990741ff083d457587665d8f620b69c3",
      "00fe6a550df547cea5b1e0d84c1a3f5f",
      "fab8b1e3187841ee894b92859fa4821b",
      "f9b0d916e1a64c2a9f384e42f3d5dcab",
      "a78199650ecc47bd81f482a2671b563a",
      "673bd3773a374261a01cfc48081c27f3",
      "83f345f7424c43929d7a304cbfb6d0fe",
      "58d69d086f644e89937347e1f9261d6f",
      "8cf462fa996c41b18fb4571e0a757363",
      "434ac4c51db74681942d2d3bd869b1df"
     ]
    },
    "id": "yAmlq_9YN4yA",
    "outputId": "263a89f7-9bee-4c6d-cf7a-7d82b0a81f92",
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.653532Z",
     "start_time": "2025-02-06T01:49:50.631146Z"
    }
   },
   "source": [
    "#载入词表，看下词表长度，词表就像英语字典,构建word2idx和idx2word\n",
    "word2idx = {\n",
    "    \"[PAD]\": 0,     # 填充 token\n",
    "    \"[BOS]\": 1,     # begin of sentence\n",
    "    \"[UNK]\": 2,     # 未知 token\n",
    "    \"[EOS]\": 3,     # end of sentence\n",
    "}\n",
    "idx2word = {value: key for key, value in word2idx.items()}\n",
    "index = len(idx2word)\n",
    "threshold = 1  # 出现次数低于此的token舍弃\n",
    "\n",
    "with open(\"wmt16/vocab\", \"r\", encoding=\"utf8\") as file:\n",
    "    for line in tqdm(file.readlines()):\n",
    "        token, counts = line.strip().split()\n",
    "        if int(counts) >= threshold:\n",
    "            word2idx[token] = index\n",
    "            idx2word[index] = token\n",
    "            index += 1\n",
    "\n",
    "vocab_size = len(word2idx)\n",
    "print(\"vocab_size: {}\".format(vocab_size))"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "  0%|          | 0/18107 [00:00<?, ?it/s]"
      ],
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "d3711cc3830149b48de8a950b4316339"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "vocab_size: 18111\n"
     ]
    }
   ],
   "execution_count": 10
  },
  {
   "cell_type": "code",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "e_ed0jmJN4yA",
    "outputId": "407a9e69-4981-42ae-c7a9-aa4c701185ef",
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.666914Z",
     "start_time": "2025-02-06T01:49:50.653532Z"
    }
   },
   "source": [
    "class Tokenizer:\n",
    "    def __init__(self, word2idx, idx2word, max_length=128, pad_idx=0, bos_idx=1, eos_idx=3, unk_idx=2):\n",
    "        self.word2idx = word2idx\n",
    "        self.idx2word = idx2word\n",
    "        self.max_length = max_length\n",
    "        self.pad_idx = pad_idx\n",
    "        self.bos_idx = bos_idx\n",
    "        self.eos_idx = eos_idx\n",
    "        self.unk_idx = unk_idx\n",
    "\n",
    "    def encode(self, text_list, padding_first=False, add_bos=True, add_eos=True, return_mask=False):\n",
    "        \"\"\"如果padding_first == True，则padding加载前面，否则加载后面\"\"\"\n",
    "        max_length = min(self.max_length, add_eos + add_bos + max([len(text) for text in text_list]))\n",
    "        indices_list = []\n",
    "        for text in text_list:\n",
    "            indices = [self.word2idx.get(word, self.unk_idx) for word in text[:max_length - add_bos - add_eos]]\n",
    "            if add_bos:\n",
    "                indices = [self.bos_idx] + indices\n",
    "            if add_eos:\n",
    "                indices = indices + [self.eos_idx]\n",
    "            if padding_first:\n",
    "                indices = [self.pad_idx] * (max_length - len(indices)) + indices\n",
    "            else:\n",
    "                indices = indices + [self.pad_idx] * (max_length - len(indices))\n",
    "            indices_list.append(indices)\n",
    "        input_ids = torch.tensor(indices_list)\n",
    "        masks = (input_ids == self.pad_idx).to(dtype=torch.int64) # 为了方便损失计算，这里的mask为0的地方需要计算，为1的地方不需要计算\n",
    "        return input_ids if not return_mask else (input_ids, masks)\n",
    "\n",
    "\n",
    "    def decode(self, indices_list, remove_bos=True, remove_eos=True, remove_pad=True, split=False):\n",
    "        text_list = []\n",
    "        for indices in indices_list:\n",
    "            text = []\n",
    "            for index in indices:\n",
    "                word = self.idx2word.get(index, \"[UNK]\")\n",
    "                if remove_bos and word == \"[BOS]\":\n",
    "                    continue\n",
    "                if remove_eos and word == \"[EOS]\":\n",
    "                    break\n",
    "                if remove_pad and word == \"[PAD]\":\n",
    "                    break\n",
    "                text.append(word)\n",
    "            text_list.append(\" \".join(text) if not split else text)\n",
    "        return text_list\n",
    "\n",
    "\n",
    "tokenizer = Tokenizer(word2idx=word2idx, idx2word=idx2word)\n",
    "\n",
    "\n",
    "raw_text = [\"hello world\".split(), \"tokenize text datas with batch\".split(), \"this is a test\".split()]\n",
    "indices = tokenizer.encode(raw_text, padding_first=False, add_bos=True, add_eos=True)\n",
    "decode_text = tokenizer.decode(indices.tolist(), remove_bos=False, remove_eos=False, remove_pad=False)\n",
    "print(\"raw text\")\n",
    "for raw in raw_text:\n",
    "    print(raw)\n",
    "print(\"indices\")\n",
    "for index in indices:\n",
    "    print(index)\n",
    "print(\"decode text\")\n",
    "for decode in decode_text:\n",
    "    print(decode)"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "raw text\n",
      "['hello', 'world']\n",
      "['tokenize', 'text', 'datas', 'with', 'batch']\n",
      "['this', 'is', 'a', 'test']\n",
      "indices\n",
      "tensor([   1, 9458, 3522,    3,    0,    0,    0])\n",
      "tensor([   1,    2, 5463,    2,   22,    2,    3])\n",
      "tensor([   1,  385,   18,    5, 5699,    3,    0])\n",
      "decode text\n",
      "[BOS] hello world [EOS] [PAD] [PAD] [PAD]\n",
      "[BOS] [UNK] text [UNK] with [UNK] [EOS]\n",
      "[BOS] this is a test [EOS] [PAD]\n"
     ]
    }
   ],
   "execution_count": 11
  },
  {
   "cell_type": "code",
   "source": [
    "for i,j in train_ds:\n",
    "    print(len(i))\n",
    "    print(len(j))\n",
    "    break"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.670059Z",
     "start_time": "2025-02-06T01:49:50.666914Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "66\n",
      "54\n"
     ]
    }
   ],
   "execution_count": 12
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "ftcEnnKxN4yB"
   },
   "source": [
    "### Transformer Batch Sampler\n",
    "\n",
    "> Sentence pairs were batched together by approximate sequence length. Each training batch contained a set of sentence pairs containing approximately 25000 source tokens and 25000 target tokens\n",
    "句子按照序列长度差不多的分到一个批次。 每个训练批次包含一组句子对，其中包含大约 25000 个源标记和 25000 个目标标记"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "qP8nznIuN4yB",
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.674404Z",
     "start_time": "2025-02-06T01:49:50.670059Z"
    }
   },
   "source": [
    "class SampleInfo: #下面的info对象\n",
    "    def __init__(self, i, lens):\n",
    "        \"\"\"\n",
    "        记录文本对的序号和长度信息\n",
    "        输入：\n",
    "            - i (int): 文本对的序号。\n",
    "            - lens (list): 文本对源语言和目标语言的长度\n",
    "        \"\"\"\n",
    "        self.i = i\n",
    "        # 加一是考虑填补在文本前后的特殊词元，lens[0]和lens[1]分别表示源语言和目标语言的长度\n",
    "        self.max_len = max(lens[0], lens[1]) + 1\n",
    "        self.src_len = lens[0] + 1\n",
    "        self.trg_len = lens[1] + 1\n",
    "\n",
    "# 一个批量生成器，根据词元数目的限制来控制批量的大小。它会根据传入的样本信息，在不超过设定大小的情况下，逐步构建批量。\n",
    "class TokenBatchCreator:\n",
    "    def __init__(self, batch_size):\n",
    "        \"\"\"\n",
    "        参数:\n",
    "        batch_size (int): 用于限制批量的大小。\n",
    "        功能:\n",
    "        初始化了一个空的批量列表 _batch。\n",
    "        设定了初始的最大长度为 -1。\n",
    "        存储了传入的 batch_size。\n",
    "        \"\"\"\n",
    "\n",
    "        self._batch = []  #这个就是之前的batch_size，就是第一个batch内有多少个样本\n",
    "        self.max_len = -1\n",
    "        self._batch_size = batch_size # 限制批量的大小,假设是4096\n",
    "\n",
    "    def append(self, info: SampleInfo):\n",
    "        \"\"\"\n",
    "        参数:\n",
    "        info (SampleInfo): 文本对的信息。\n",
    "        功能:\n",
    "        接收一个 SampleInfo 对象，并根据其最大长度信息更新当前批量的最大长度。\n",
    "        如果将新的样本加入批量后超过了批量大小限制，它会返回已有的批量并将新的样本加入新的批量。\n",
    "        否则，它会更新最大长度并将样本添加到当前批量中。\n",
    "        \"\"\"\n",
    "        # 更新当前批量的最大长度\n",
    "        cur_len = info.max_len # 当前样本的长度\n",
    "        max_len = max(self.max_len, cur_len) # 每来一个样本，更新当前批次的最大长度\n",
    "        # 如果新的样本加入批量后超过大小限制，则将已有的批量返回，新的样本加入新的批量\n",
    "        if max_len * (len(self._batch) + 1) > self._batch_size:\n",
    "            self._batch, result = [], self._batch # 保存当前的batch，并返回,这里的result是之前的batch,_batch清空\n",
    "            self._batch.append(info) #箱子里的第一条样本，放入\n",
    "            self.max_len = cur_len #因为是当前batch的第一个样本，所以它的长度就是当前长度\n",
    "            return result\n",
    "        else:\n",
    "            self.max_len = max_len\n",
    "            self._batch.append(info) # 将样本添加到当前批量中\n",
    "            return None\n",
    "\n",
    "    @property\n",
    "    def batch(self):\n",
    "        return self._batch"
   ],
   "outputs": [],
   "execution_count": 13
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "_Vtc0gXEN4yB",
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.680427Z",
     "start_time": "2025-02-06T01:49:50.676008Z"
    }
   },
   "source": [
    "from torch.utils.data import BatchSampler\n",
    "import numpy as np\n",
    "\n",
    "\n",
    "class TransformerBatchSampler(BatchSampler):\n",
    "    def __init__(self,\n",
    "                 dataset,\n",
    "                 batch_size,\n",
    "                 shuffle_batch=False,\n",
    "                 clip_last_batch=False,\n",
    "                 seed=0):\n",
    "        \"\"\"\n",
    "        批量采样器\n",
    "        输入:\n",
    "            - dataset: 数据集\n",
    "            - batch_size: 批量大小\n",
    "            - shuffle_batch: 是否对生成的批量进行洗牌\n",
    "            - clip_last_batch: 是否裁剪最后剩下的数据\n",
    "            - seed: 随机数种子\n",
    "        \"\"\"\n",
    "        self._dataset = dataset\n",
    "        self._batch_size = batch_size\n",
    "        self._shuffle_batch = shuffle_batch\n",
    "        self._clip_last_batch = clip_last_batch\n",
    "        self._seed = seed #下面3个是为了随机\n",
    "        self._random = np.random\n",
    "        self._random.seed(seed)\n",
    "\n",
    "        self._sample_infos = []\n",
    "        # 根据数据集中的每个样本，创建了对应的 SampleInfo 对象，包含了样本的索引和长度信息。\n",
    "        for i, data in enumerate(self._dataset):\n",
    "            lens = [len(data[0]), len(data[1])] #输入和输出的长度计算放到lens中\n",
    "            self._sample_infos.append(SampleInfo(i, lens))\n",
    "\n",
    "    def __iter__(self):\n",
    "        \"\"\"\n",
    "        对数据集中的样本进行排序，排序规则是先按源语言长度排序，如果相同则按目标语言长度排序。\n",
    "        使用 TokenBatchCreator 逐步组装批量数据，当满足批量大小时返回一个批量的样本信息。\n",
    "        如果不裁剪最后一个批次的数据且存在剩余样本，则将这些样本组成最后一个批次。\n",
    "        如果需要对批量进行洗牌，则对批次进行洗牌操作。\n",
    "        通过迭代器，抛出每个批量的样本在数据集中的索引。\n",
    "        \"\"\"\n",
    "        # 排序，如果源语言长度相同则按照目标语言的长度排列\n",
    "        infos = sorted(self._sample_infos,\n",
    "                       key=lambda x: (x.src_len, x.trg_len))\n",
    "        # 把样本放入到箱子里，所有装箱后的箱子，每一个箱子都放入batch_infos\n",
    "        batch_infos = []\n",
    "        batch_creator = TokenBatchCreator(self._batch_size) # 批量生成器\n",
    "        for info in infos:\n",
    "            batch = batch_creator.append(info)\n",
    "            # 存够一个batch的样本信息后，会把这个batch返回，否则返回为None\n",
    "            if batch is not None:\n",
    "                batch_infos.append(batch)\n",
    "\n",
    "        # 是否抛弃最后批量的文本对\n",
    "        if not self._clip_last_batch and len(batch_creator.batch) != 0:\n",
    "            batch_infos.append(batch_creator.batch) # 最后一个batch\n",
    "\n",
    "        # 打乱batch，打乱的是箱子的顺序\n",
    "        if self._shuffle_batch:\n",
    "            self._random.shuffle(batch_infos)\n",
    "\n",
    "        self.batch_number = len(batch_infos)\n",
    "        # print(self.batch_number) #为了理解\n",
    "\n",
    "        # 抛出一个箱子里所有样本的序号\n",
    "        for batch in batch_infos:\n",
    "            batch_indices = [info.i for info in batch] # 批量的样本在数据集中的索引，第一个batch[0,1,.....82]，第二个batch[83,84,85,86,87]\n",
    "            yield batch_indices\n",
    "\n",
    "    def __len__(self):\n",
    "        \"\"\"\n",
    "        返回批量的数量\n",
    "        \"\"\"\n",
    "        if hasattr(self, \"batch_number\"):\n",
    "            return self.batch_number\n",
    "        # 计算批量的数量,没有用到下面的情况，不用看\n",
    "        batch_number = (len(self._dataset) +\n",
    "                        self._batch_size) // self._batch_size\n",
    "        return batch_number"
   ],
   "outputs": [],
   "execution_count": 14
  },
  {
   "cell_type": "code",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "d00AFRzVN4yC",
    "outputId": "a43c1a14-102f-4cbb-fff1-761cb46e31b3",
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.725998Z",
     "start_time": "2025-02-06T01:49:50.680427Z"
    }
   },
   "source": [
    "sampler = TransformerBatchSampler(train_ds, batch_size=4096, shuffle_batch=True)\n",
    "\n",
    "#为什么这里每个批量的样本对数目不一样呢？长度*batch_number>4096的时候，就会返回上一个batch，然后新的样本加入新的batch,具体要看TokenBatchCreator的44行"
   ],
   "outputs": [],
   "execution_count": 15
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.750597Z",
     "start_time": "2025-02-06T01:49:50.727002Z"
    }
   },
   "cell_type": "code",
   "source": [
    "for i in sampler:\n",
    "    print(i)\n",
    "    break"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[26845, 982, 1864, 3222, 4716, 5341, 5897, 6103, 8531, 10067, 11125, 13063, 14929, 15158, 18063, 18502, 20661, 20986, 21320, 22030, 22882, 23567, 24909, 1881, 2268, 4268, 7413, 10166, 12447, 13573, 15332, 16727, 17657, 20829, 21508, 23094, 24274, 25801, 518, 2145, 4111, 4739, 4745, 7493, 7623, 8369, 8618, 8730, 9054, 9391, 9808, 10141, 10412, 11422, 13534, 15038]\n"
     ]
    }
   ],
   "execution_count": 16
  },
  {
   "cell_type": "code",
   "source": [
    "for idx, batch in enumerate(sampler):\n",
    "    print(\"第{}批量的数据中含有文本对是：{}，数量为：{}\".format(idx, batch, len(batch)))\n",
    "    if idx >= 3:\n",
    "        break"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.776565Z",
     "start_time": "2025-02-06T01:49:50.751603Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "第0批量的数据中含有文本对是：[21271, 22083, 25959, 49, 637, 6773, 8687, 16391, 19042, 22788, 22867, 27194, 2246, 11350, 12499, 14881, 16713, 20199, 17560, 23179, 6216, 18973, 19368, 25486, 15211, 17452, 17890, 19236, 25288, 27115, 2627, 19805, 755, 10914, 16360, 21301, 27624, 7114]，数量为：38\n",
      "第1批量的数据中含有文本对是：[25919, 26342, 1164, 1463, 4572, 4601, 4923, 5629, 10667, 12481, 13313, 13485, 15766, 16256, 19927, 20233, 21061, 27843, 1040, 2768, 4096, 5842, 5847, 6265, 6663, 8346, 8481, 10076, 14832, 17516, 18001, 21196, 22517, 23172, 23181, 23604, 27227, 27892, 3, 120, 607, 2870, 3270, 9536, 10044, 11085, 15960, 21744, 22156, 22189, 24491, 27443, 151]，数量为：53\n",
      "第2批量的数据中含有文本对是：[23598, 26090, 26756, 27395, 6244, 10461, 12839, 16355, 20300, 21417, 26565, 4264, 4307, 6294, 7085, 9525, 9559, 9647, 9710, 10344, 12214, 13075, 13337, 13691, 16381, 19796, 21830, 23531, 25014, 25921, 27752, 1850, 4221, 5306, 8341, 8859, 9052, 10025, 11858, 11948, 15347, 15812, 18069, 18469, 22704, 23203, 23537, 26233, 26928, 27214, 179, 1745, 4982]，数量为：53\n",
      "第3批量的数据中含有文本对是：[17510, 26533, 12808, 1291, 11297, 19038, 24464, 1494, 3332, 3655, 15580, 24842, 1275, 7737, 16751, 16762, 21651, 24549, 25529, 26103, 4049, 4332, 23891, 24659, 25552, 27437, 1112, 6020, 24492, 14171, 17259, 19267, 26181, 26556, 2919, 3983, 998, 26712, 24446]，数量为：39\n"
     ]
    }
   ],
   "execution_count": 17
  },
  {
   "cell_type": "code",
   "source": [
    "len(sampler)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.779581Z",
     "start_time": "2025-02-06T01:49:50.776565Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "527"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 18
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Olkaw4JNN4yC"
   },
   "source": [
    "### DataLoader"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "rvvuNJIzN4yC",
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.782910Z",
     "start_time": "2025-02-06T01:49:50.779581Z"
    }
   },
   "source": [
    "def collate_fct(batch, tokenizer):\n",
    "    src_words = [pair[0].split() for pair in batch]\n",
    "    trg_words = [pair[1].split() for pair in batch]\n",
    "\n",
    "    # [BOS] src [EOS] [PAD]\n",
    "    encoder_inputs, encoder_inputs_mask = tokenizer.encode(\n",
    "        src_words, padding_first=False, add_bos=True, add_eos=True, return_mask=True\n",
    "        )\n",
    "\n",
    "    # [BOS] trg [PAD]\n",
    "    decoder_inputs = tokenizer.encode(\n",
    "        trg_words, padding_first=False, add_bos=True, add_eos=False, return_mask=False,\n",
    "        )\n",
    "\n",
    "    # trg [EOS] [PAD]\n",
    "    decoder_labels, decoder_labels_mask = tokenizer.encode(\n",
    "        trg_words, padding_first=False, add_bos=False, add_eos=True, return_mask=True\n",
    "        )\n",
    "\n",
    "    return {\n",
    "        \"encoder_inputs\": encoder_inputs.to(device=device),\n",
    "        \"encoder_inputs_mask\": encoder_inputs_mask.to(device=device),\n",
    "        \"decoder_inputs\": decoder_inputs.to(device=device),\n",
    "        \"decoder_labels\": decoder_labels.to(device=device),\n",
    "        \"decoder_labels_mask\": decoder_labels_mask.to(device=device),\n",
    "    }\n"
   ],
   "outputs": [],
   "execution_count": 19
  },
  {
   "cell_type": "code",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "5p79gPo5N4yC",
    "outputId": "2b1d43ae-a2ed-4333-8274-50c62c2fc6c9",
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.830190Z",
     "start_time": "2025-02-06T01:49:50.782910Z"
    }
   },
   "source": [
    "from functools import partial # 固定collate_fct的tokenizer参数\n",
    "\n",
    "#可以调大batch_size,来看最终的bleu，如果GPU内存不够，可以减小batch_size\n",
    "sampler = TransformerBatchSampler(train_ds, batch_size=256, shuffle_batch=True)\n",
    "# https://pytorch.org/docs/stable/data.html#torch.utils.data.DataLoader\n",
    "sample_dl = DataLoader(train_ds, batch_sampler=sampler, collate_fn=partial(collate_fct, tokenizer=tokenizer)) #partial函数，固定collate_fct的tokenizer参数\n",
    "\n",
    "for batch in sample_dl:#外层是拿每个batch\n",
    "    for key, value in batch.items():#内层是拿每个batch里面是一个字典\n",
    "        print(key)\n",
    "        print(value)\n",
    "    break"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "encoder_inputs\n",
      "tensor([[    1,     7,    17,     6,  4636,  3116,    31, 13407,     4,     3,\n",
      "             0,     0,     0],\n",
      "        [    1,  1310,    12,  2275,  6752,  1029,  8834, 13522,     4,     3,\n",
      "             0,     0,     0],\n",
      "        [    1,    84,    58,   172,   288,     9,    29,    98,    12,    21,\n",
      "            52,     4,     3],\n",
      "        [    1,    17,     6,   488,   442,    12,   499,   199,    73,    11,\n",
      "           235,     4,     3]])\n",
      "encoder_inputs_mask\n",
      "tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])\n",
      "decoder_inputs\n",
      "tensor([[   1,    5,  324,   36, 2123,  672,   18, 2497,    5, 3739, 2933,    4,\n",
      "            0,    0],\n",
      "        [   1,    5, 1270,   19, 2409,   30, 2698,  307,  136, 1213, 1174,    4,\n",
      "            0,    0],\n",
      "        [   1,   87,   51,   30,  242,    9,   28,   53,   19,   83,   62,    4,\n",
      "            0,    0],\n",
      "        [   1,    5,   16,   36,    5,   45,  362,   19,   55,   80,  265,    5,\n",
      "          219,    4]])\n",
      "decoder_labels\n",
      "tensor([[   5,  324,   36, 2123,  672,   18, 2497,    5, 3739, 2933,    4,    3,\n",
      "            0,    0],\n",
      "        [   5, 1270,   19, 2409,   30, 2698,  307,  136, 1213, 1174,    4,    3,\n",
      "            0,    0],\n",
      "        [  87,   51,   30,  242,    9,   28,   53,   19,   83,   62,    4,    3,\n",
      "            0,    0],\n",
      "        [   5,   16,   36,    5,   45,  362,   19,   55,   80,  265,    5,  219,\n",
      "            4,    3]])\n",
      "decoder_labels_mask\n",
      "tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])\n"
     ]
    }
   ],
   "execution_count": 20
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "0AadtoM3N4yC"
   },
   "source": [
    "## 定义模型\n",
    "\n",
    "- Transformer模型由Embedding、Transformer-Block组成\n",
    "- Embedding包括：\n",
    "    - WordEmbedding\n",
    "    - PositionEmbedding\n",
    "- Transformer-Block包括：\n",
    "    - Self-Attention\n",
    "    - Cross-Attention\n",
    "    - MLP"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "VTl-sSJmN4yD"
   },
   "source": [
    "### Embedding"
   ]
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.834899Z",
     "start_time": "2025-02-06T01:49:50.831210Z"
    }
   },
   "cell_type": "code",
   "source": "torch.arange(0, 128).unsqueeze(1).shape",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([128, 1])"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 21
  },
  {
   "cell_type": "code",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 455
    },
    "id": "y66CxrsBN4yD",
    "outputId": "c703025c-afc5-4012-d8e3-0e9d4ad253ec",
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.956649Z",
     "start_time": "2025-02-06T01:49:50.834899Z"
    }
   },
   "source": [
    "\n",
    "class TransformerEmbedding(nn.Module):\n",
    "    def __init__(self, config):\n",
    "        super().__init__()\n",
    "        # hyper params\n",
    "        self.vocab_size = config[\"vocab_size\"]\n",
    "        self.hidden_size = config[\"d_model\"] # 词向量维度\n",
    "        self.pad_idx = config[\"pad_idx\"]\n",
    "        dropout_rate = config[\"dropout\"]\n",
    "        self.max_length = config[\"max_length\"]\n",
    "\n",
    "        # layers,设置padding_idx可以让pad的词向量全为0\n",
    "        self.word_embedding = nn.Embedding(\n",
    "            self.vocab_size, self.hidden_size, padding_idx=self.pad_idx\n",
    "        )\n",
    "        self.pos_embedding = nn.Embedding(\n",
    "            self.max_length,\n",
    "            self.hidden_size,\n",
    "            _weight=self.get_positional_encoding(\n",
    "                self.max_length, self.hidden_size\n",
    "            ),# 位置编码，权重通过get_positional_encoding函数计算得到\n",
    "        )\n",
    "        self.pos_embedding.weight.requires_grad_(False) # 不更新位置编码的权重\n",
    "        self.dropout = nn.Dropout(dropout_rate) # 随机失活层\n",
    "\n",
    "    def get_word_embedding_weights(self):\n",
    "        return self.word_embedding.weight\n",
    "\n",
    "    # 计算位置信息\n",
    "    @classmethod\n",
    "    def get_positional_encoding(self, max_length, hidden_size):#max_length是最大长度，hidden_size是embedding维度相等\n",
    "        # Compute the positional encodings once in log space.\n",
    "        pe = torch.zeros(max_length, hidden_size) # 初始化位置编码\n",
    "        # .unsqueeze(1) 是将这个一维张量转换为二维张量，即将其形状从 (max_length,) 变为 (max_length, 1)。这个操作在张量的维度上增加了一个维度，使其从一维变为二维，第二维的大小为 1。\n",
    "        position = torch.arange(0, max_length).unsqueeze(1) # 位置信息,从0到max_length-1\n",
    "        div_term = torch.exp(\n",
    "            torch.arange(0, hidden_size, 2)\n",
    "            * -(torch.log(torch.Tensor([10000.0])) / hidden_size)\n",
    "        )# 计算位置编码的权重,为了性能考量（是数学上的对数函数分解）\n",
    "        pe[:, 0::2] = torch.sin(position * div_term)\n",
    "        pe[:, 1::2] = torch.cos(position * div_term)\n",
    "        return pe\n",
    "\n",
    "    def forward(self, input_ids):\n",
    "        # input_ids: [batch_size, seq_len]\n",
    "        seq_len = input_ids.shape[1]\n",
    "        assert (\n",
    "            seq_len <= self.max_length\n",
    "        ), f\"input sequence length should no more than {self.max_length} but got {seq_len}\"\n",
    "\n",
    "        position_ids = torch.arange(seq_len, dtype=torch.long, device=input_ids.device)\n",
    "        position_ids = position_ids.unsqueeze(0).expand_as(input_ids)\n",
    "        print(position_ids) #为了调试\n",
    "        # embedding\n",
    "        word_embeds = self.word_embedding(input_ids) # 词嵌入\n",
    "        pos_embeds = self.pos_embedding(position_ids) # 位置编码\n",
    "        embeds = word_embeds + pos_embeds\n",
    "        embeds = self.dropout(embeds)\n",
    "\n",
    "        return embeds\n",
    "\n",
    "\n",
    "def plot_position_embedding(position_embedding):# 绘制位置编码\n",
    "    plt.pcolormesh(position_embedding) # 绘制位置编码矩阵\n",
    "    plt.xlabel('Depth')\n",
    "    plt.ylabel('Position')\n",
    "    plt.colorbar() # 颜色条，-1到1的颜色范围\n",
    "    plt.show()\n",
    "\n",
    "position_embedding = TransformerEmbedding.get_positional_encoding(64, 128)\n",
    "plot_position_embedding(position_embedding)\n"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 2 Axes>"
      ],
      "image/png": "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"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 22
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.960602Z",
     "start_time": "2025-02-06T01:49:50.957655Z"
    }
   },
   "cell_type": "code",
   "source": [
    "import math\n",
    "#为了理解指数对数变换\n",
    "def positional_encoding_weights(emb_size):\n",
    "    # 计算底数和指数\n",
    "    base = math.log(10000)\n",
    "    exponent = -5 / emb_size\n",
    "    \n",
    "    # 应用指数函数\n",
    "    weight = math.exp(exponent*base) \n",
    "    \n",
    "    return weight\n",
    "\n",
    "emb_size = 10  # 举例，可以替换成你需要的大小\n",
    "weight = positional_encoding_weights(emb_size)\n",
    "print(weight)"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.009999999999999995\n"
     ]
    }
   ],
   "execution_count": 23
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.966300Z",
     "start_time": "2025-02-06T01:49:50.961609Z"
    }
   },
   "cell_type": "code",
   "source": "1/10000**(1/2)",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.01"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 24
  },
  {
   "cell_type": "code",
   "source": [
    "#随机input，调用TransformerEmbedding\n",
    "config={\n",
    "    \"vocab_size\": 100,\n",
    "    \"d_model\": 128,\n",
    "    \"pad_idx\": 0,\n",
    "    \"max_length\": 64,\n",
    "    \"dropout\": 0.1,\n",
    "}\n",
    "input_ids = torch.randint(0, 100, (2, 50))\n",
    "embeds = TransformerEmbedding(config)(input_ids)\n",
    "embeds.shape"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:50.974674Z",
     "start_time": "2025-02-06T01:49:50.967307Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,\n",
      "         18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,\n",
      "         36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49],\n",
      "        [ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,\n",
      "         18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,\n",
      "         36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49]])\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "torch.Size([2, 50, 128])"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 25
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "wXavO0SNN4yD"
   },
   "source": [
    "### Transformer Block"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "HZL4mu3pN4yD"
   },
   "source": [
    "#### scaled-dot-product-attention"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 970
    },
    "id": "U9QwdVQYN4yD",
    "outputId": "b6ae9ac8-c71c-4a7b-fd4b-9c15e92dba2c",
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:51.072130Z",
     "start_time": "2025-02-06T01:49:50.974674Z"
    }
   },
   "source": [
    "from dataclasses import dataclass\n",
    "from typing import Optional, Tuple\n",
    "\n",
    "Tensor = torch.Tensor\n",
    "\n",
    "@dataclass\n",
    "class AttentionOutput:\n",
    "    hidden_states: Tensor\n",
    "    attn_scores: Tensor\n",
    "\n",
    "class MultiHeadAttention(nn.Module):\n",
    "    def __init__(self, config):\n",
    "        super().__init__()\n",
    "        # hyper params\n",
    "        self.hidden_size = config[\"d_model\"] # 隐藏层大小\n",
    "        self.num_heads = config[\"num_heads\"] # 多头注意力的头数\n",
    "        assert (\n",
    "            self.hidden_size % self.num_heads == 0\n",
    "        ), \"Hidden size must be divisible by num_heads but got {} and {}\".format(\n",
    "            self.hidden_size, self.num_heads\n",
    "        )\n",
    "        self.head_dim = self.hidden_size // self.num_heads # 每个头的维度\n",
    "\n",
    "        # layers\n",
    "        self.Wq = nn.Linear(self.hidden_size, self.hidden_size, bias=False) #第二个self.hidden_size可以*系数\n",
    "        self.Wk = nn.Linear(self.hidden_size, self.hidden_size, bias=False)\n",
    "        self.Wv = nn.Linear(self.hidden_size, self.hidden_size, bias=False)\n",
    "        self.Wo = nn.Linear(self.hidden_size, self.hidden_size, bias=False) # 输出层\n",
    "\n",
    "    def _split_heads(self, x: Tensor) -> Tensor:\n",
    "        bs, seq_len, _ = x.shape #假设输入的维度是[batch_size, seq_len, hidden_size],hidden_size是512\n",
    "        x = x.view(bs, seq_len, self.num_heads, self.head_dim) #num_heads是8，head_dim是64\n",
    "        return x.permute(0, 2, 1, 3) #变换维度，[batch_size, num_heads, seq_len, head_dim]\n",
    "\n",
    "    def _merge_heads(self, x: Tensor) -> Tensor:#将多头注意力的输出合并为一个张量\n",
    "        bs, _, seq_len, _ = x.shape #假设输入的维度是[batch_size, num_heads, seq_len, head_dim]\n",
    "        return x.permute(0, 2, 1, 3).reshape(bs, seq_len, self.hidden_size) # 变换维度，变为[batch_size, seq_len, hidden_size]\n",
    "\n",
    "    def forward(self, querys, keys, values, attn_mask=None) -> AttentionOutput:\n",
    "        # split heads\n",
    "        querys = self._split_heads(self.Wq(querys)) #(batch_size, seq_len,hidden_dim)-->[batch_size, num_heads, seq_len, head_dim]\n",
    "        keys = self._split_heads(self.Wk(keys))#[batch_size, num_heads, seq_len, head_dim]\n",
    "        values = self._split_heads(self.Wv(values))#[batch_size, num_heads, seq_len, head_dim]\n",
    "\n",
    "        # calculate attention scores\n",
    "        qk_logits = torch.matmul(querys, keys.mT) # 计算注意力分数，matmul是矩阵乘法，mT是矩阵转置,qk_logits是[batch_size, num_heads, seq_len, seq_len]\n",
    "        # print(querys.shape[-2], keys.shape[-2])  #3 4\n",
    "        if attn_mask is not None:\n",
    "            attn_mask = attn_mask[:, :, : querys.shape[-2], : keys.shape[-2]]\n",
    "            qk_logits += attn_mask * -1e9 # 给需要mask的地方设置一个负无穷\n",
    "        attn_scores = F.softmax(qk_logits / (self.head_dim**0.5), dim=-1) # 计算注意力分数\n",
    "\n",
    "        # embeds的尺寸是[batch_size, num_heads, seq_len, head_dim]\n",
    "        embeds = torch.matmul(attn_scores, values) # softmax后的结果与value相乘，得到新的表示\n",
    "        embeds = self.Wo(self._merge_heads(embeds)) # 输出层 [batch_size, seq_len, hidden_size]\n",
    "\n",
    "        return AttentionOutput(hidden_states=embeds, attn_scores=attn_scores)\n",
    "\n",
    "mha = MultiHeadAttention({\"num_heads\": 2, \"d_model\": 2})\n",
    "query = torch.randn(2, 3, 2) # [batch_size, seq_len, hidden_size]\n",
    "query /= query.norm(dim=-1, keepdim=True) # 归一化\n",
    "key_value = torch.randn(2, 4, 2)\n",
    "print(f'key_value.shape {key_value.shape}')\n",
    "outputs = mha(query, key_value, key_value) #最终输出shape和query的shape一样\n",
    "print(outputs.hidden_states.shape)\n",
    "print(outputs.attn_scores.shape)"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "key_value.shape torch.Size([2, 4, 2])\n",
      "torch.Size([2, 3, 2])\n",
      "torch.Size([2, 2, 3, 4])\n"
     ]
    }
   ],
   "execution_count": 26
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:51.077559Z",
     "start_time": "2025-02-06T01:49:51.072130Z"
    }
   },
   "cell_type": "code",
   "source": [
    "#随机一个2阶张量，在-1维度计算softmax\n",
    "import torch.nn.functional as F\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "\n",
    "x = torch.randn(2, 3)\n",
    "x_softmax = F.softmax(x, dim=-1)\n",
    "print(x_softmax)\n",
    "\n"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[0.7946, 0.1312, 0.0741],\n",
      "        [0.2836, 0.2315, 0.4849]])\n"
     ]
    }
   ],
   "execution_count": 27
  },
  {
   "cell_type": "code",
   "source": [
    "# plt.subplots() 用于创建子图网格，其维度基于 outputs.attn_scores.shape[:2]。子图的行数和列数似乎由 outputs.attn_scores 的前两个维度确定。\n",
    "fig, axis = plt.subplots(*outputs.attn_scores.shape[:2])\n",
    "for i in range(query.shape[0]):\n",
    "    for j in range(outputs.attn_scores.shape[1]):\n",
    "        # axis[i, j].matshow(outputs.attn_scores[i, j].detach().numpy())：此行使用 Matplotlib 的 matshow 绘制每个 i 和 j 的注意力分数热图。detach().numpy() 将 PyTorch 张量转换为 NumPy 数组以进行可视化。\n",
    "        axis[i, j].matshow(outputs.attn_scores[i, j].detach().numpy())\n",
    "        for x in range(outputs.attn_scores.shape[2]):\n",
    "            for y in range(outputs.attn_scores.shape[3]):\n",
    "                # axis[i, j].text(y, x, f\"{outputs.attn_scores[i, j, x, y]:.2f}\", ha=\"center\", va=\"center\", color=\"w\")：此代码在热图上叠加文本，显示 (x, y) 位置处的注意力分数。格式化部分 f\"{outputs.attn_scores[i, j, x, y]:.2f}\" 确保以两位小数显示注意力分数。文本以白色居中显示在 (y, x) 坐标处。\n",
    "                axis[i, j].text(y, x, f\"{outputs.attn_scores[i, j, x, y]:.2f}\", ha=\"center\", va=\"center\", color=\"w\")\n",
    "fig.suptitle(\"multi head attention without mask\")\n",
    "plt.show()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:51.232825Z",
     "start_time": "2025-02-06T01:49:51.078579Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 4 Axes>"
      ],
      "image/png": "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"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 28
  },
  {
   "cell_type": "code",
   "source": [
    "print('-'*50)\n",
    "# mask\n",
    "mask = torch.Tensor([[0, 0, 1, 1], [0, 0, 0, 1], [0, 0, 0, 0]]).reshape(1, 1, 3, 4) #手工构造mask\n",
    "outputs_masked = mha(query, key_value, key_value, mask)\n",
    "\n",
    "fig, axis = plt.subplots(*outputs_masked.attn_scores.shape[:2])\n",
    "for i in range(query.shape[0]):\n",
    "    for j in range(outputs_masked.attn_scores.shape[1]):\n",
    "        axis[i, j].matshow(outputs_masked.attn_scores[i, j].detach().numpy())\n",
    "        for x in range(outputs_masked.attn_scores.shape[2]):\n",
    "            for y in range(outputs_masked.attn_scores.shape[3]):\n",
    "                axis[i, j].text(y, x, f\"{outputs_masked.attn_scores[i, j, x, y]:.2f}\", ha=\"center\", va=\"center\", color=\"w\")\n",
    "fig.suptitle(\"multi head attention with mask\")\n",
    "plt.show()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:51.374525Z",
     "start_time": "2025-02-06T01:49:51.232825Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--------------------------------------------------\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 4 Axes>"
      ],
      "image/png": "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PS87bIpEQXRgEUMNn124DsmlXx6eznYoFt1mS43p0Q7mZmp8PmWo1nK++fsgvv07RP7du21TmaiU+Xjy4JvK6MvGKxFy3PWMDj3kQSCGQz2+fQUSc0vi87Kx14pPHFTvdXkADaztkFtUiItpSZi+90+5nLvRluOl229QsOxce+5aAp79ptL2c6qy/bq1g7lajc+fqLL9Nh3Et5tKt1+bpjJRKfPxpME3ldGXzafPy3HlIlEQ+6cY7jV1ybryDlgNHLXjG9+5JL75j2jHt3DHQSzcod91r2uGrjv+PnseztbWeLFHV7jZWMuhok+sXIuk0s6bXvZ2MvEp81DHkm2zYKT2tvly70F8te8g7jZ/nSuJb3q3rjJBEP0fJq2uiK+Bvfa+90j7drBQq/H1MO345h84iC8PlMS3NTIS/7dtO57pHIS3+tyHSynJeG7DnzgWc13P0QEbL4m60UomCqJzZnhSPB7ftKq882bVuvHRezvKE61v7x+utZwvju3HvNCSL2Z3axv8X5f75GWU+OxMrL1wBl8ePwBD2HyqpO4QiYKsO64nYOpi7bqj8v45rkvJ/jnvsSp1x7aD+Hp7Sd1xX6umeH9sRd342SODbypTF1Saymt6u8LVdGBZsmSJHC5WE+LaqKhIWj/5AUzNLWGMUgPzYMwcjynTLH03K9BvB3C9KcrLxfnPX5ejL+zt7fX2vv+27iirN5q89T5MLI2z3ijW/z2X9KrQQf83zdI320gzo603zs2vWb1R68sfRES1xbqD6L+BPyhGREREimBSQURERIpgUkFERESKYFJBREREimBSQURERIpgUkFERESKYFJBREREimBSQURERIpgUkFERESKYFJBREREimBSQURERIpgUkFERESKYFJBREREimBSQURERIpgUkFERESKYFJBREREimBSQURERIpgUkFERESKYFJBREREimBSQURERIpQQ880Go38vyg/F8aqOCcPxqwov2QbGrMiI92ERXm5WsdhfVG2vsWl62+Miotg1IrNC2HsivKMcyPWpt5QafRcu1y7dg0+Pj76fEsiqiI6Ohre3t6oL1hvENWPekPvSUVxcTGuX78OOzs7qFSqOn+/9PR0WRmJD8Pe3h7GhvHVb/qOTxzuGRkZ8PLygolJ/bn6yXpDWYyvfku/i+sNvV/+ECtkiDMk8cEb485VhvHVb/qMz8HBAfUN6426wfjqN/u7sN6oP6cqREREdFdjUkFERESKMPqkwsLCArNnz5b/GyPGV78Ze3z1lbFvF8ZXv1ncxfHpvaMmERERGSejb6kgIiIi/WBSQURERIpgUkFERESKYFJBREREimBSQURERIpgUkFERESKYFJBREREimBSQURERFDC/wNKzsrMrz7UzgAAAABJRU5ErkJggg=="
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 29
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "GkzzrRWVN4yE"
   },
   "source": [
    "#### Transformer-Block"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "b16xpL47N4yE",
    "ExecuteTime": {
     "end_time": "2025-02-06T01:49:51.380023Z",
     "start_time": "2025-02-06T01:49:51.374525Z"
    }
   },
   "source": [
    "# 通过使用 @dataclass 装饰器，Python 会自动为该类生成一些方法，如 __init__()、__repr__() 和 __eq__() 等，这些方法可以使类的使用更加方便。\n",
    "@dataclass\n",
    "class TransformerBlockOutput:\n",
    "# hidden_states: Tensor：用于存储某个块产生的隐藏状态。\n",
    "# self_attn_scores: Tensor：包含了自注意力机制（self-attention）所计算得到的注意力分数。\n",
    "# cross_attn_scores: Optional[Tensor] = None：是一个可选字段，存储了交叉注意力（cross-attention）计算得到的注意力分数。这里的 Optional 表示这个字段可以是 Tensor 类型，也可以是 None。\n",
    "    hidden_states: Tensor\n",
    "    self_attn_scores: Tensor\n",
    "    cross_attn_scores: Optional[Tensor] = None\n",
    "\n",
    "class TransformerBlock(nn.Module):\n",
    "    def __init__(self, config, add_cross_attention=False):\n",
    "        super().__init__()\n",
    "        # hyper params\n",
    "        self.hidden_size = config[\"d_model\"]\n",
    "        self.num_heads = config[\"num_heads\"]\n",
    "        dropout_rate = config[\"dropout\"]\n",
    "        ffn_dim = config[\"dim_feedforward\"]\n",
    "        eps = config[\"layer_norm_eps\"] # 层归一化的epsilon值\n",
    "\n",
    "        # self-attention\n",
    "        self.self_atten = MultiHeadAttention(config) # 多头注意力\n",
    "        self.self_ln = nn.LayerNorm(self.hidden_size, eps=eps) #层归一化(层标准化)\n",
    "        self.self_dropout = nn.Dropout(dropout_rate)\n",
    "\n",
    "        # cross-attention，交叉注意力，decoder中使用,因此额外做一个判断\n",
    "        if add_cross_attention:\n",
    "            self.cross_atten = MultiHeadAttention(config)\n",
    "            self.cross_ln = nn.LayerNorm(self.hidden_size, eps=eps)\n",
    "            self.cross_dropout = nn.Dropout(dropout_rate)\n",
    "        else:\n",
    "            self.cross_atten = None\n",
    "\n",
    "        # FFN,前馈神经网络\n",
    "        self.ffn = nn.Sequential(\n",
    "            nn.Linear(self.hidden_size, ffn_dim),\n",
    "            nn.ReLU(),\n",
    "            nn.Linear(ffn_dim, self.hidden_size),\n",
    "        )\n",
    "        self.ffn_ln = nn.LayerNorm(self.hidden_size, eps=eps)\n",
    "        self.ffn_dropout = nn.Dropout(dropout_rate)\n",
    "\n",
    "    def forward(\n",
    "        self,\n",
    "        hidden_states,\n",
    "        attn_mask=None,\n",
    "        encoder_outputs=None,\n",
    "        cross_attn_mask=None,\n",
    "    ):\n",
    "        # self-attention,自注意力\n",
    "        self_atten_output = self.self_atten(\n",
    "            hidden_states, hidden_states, hidden_states, attn_mask\n",
    "        )\n",
    "        self_embeds = self.self_ln(\n",
    "            hidden_states + self.self_dropout(self_atten_output.hidden_states)\n",
    "        ) #多头注意力进行dropout，然后和原始输入进行残差连接，然后进行层归一化\n",
    "\n",
    "        # cross-attention，交叉注意力\n",
    "        if self.cross_atten is not None:\n",
    "            assert encoder_outputs is not None\n",
    "            cross_atten_output = self.cross_atten(\n",
    "                self_embeds, encoder_outputs, encoder_outputs, cross_attn_mask\n",
    "            ) #query是self_embeds，key和value都是encoder_outputs\n",
    "            cross_embeds = self.cross_ln(\n",
    "                self_embeds + self.cross_dropout(cross_atten_output.hidden_states)\n",
    "            ) # 交叉注意力进行dropout，然后和self_embeds进行残差连接，然后进行层归一化\n",
    "\n",
    "        # FFN\n",
    "        embeds = cross_embeds if self.cross_atten is not None else self_embeds # 如果有交叉注意力，则使用交叉注意力的输出作为FFN的输入；否则，使用self_embeds作为FFN的输入\n",
    "        ffn_output = self.ffn(embeds) # 前馈神经网络\n",
    "        embeds = self.ffn_ln(embeds + self.ffn_dropout(ffn_output)) # 前馈神经网络进行dropout，然后和原始输入进行残差连接，然后进行层归一化\n",
    "\n",
    "        return TransformerBlockOutput(\n",
    "            hidden_states=embeds,\n",
    "            self_attn_scores=self_atten_output.attn_scores,\n",
    "            cross_attn_scores=cross_atten_output.attn_scores\n",
    "            if self.cross_atten is not None\n",
    "            else None,\n",
    "        )"
   ],
   "outputs": [],
   "execution_count": 30
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "tfJIGaohN4yE"
   },
   "source": [
    "#### Encoder"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "sTLabHm7N4yE",
    "ExecuteTime": {
     "end_time": "2025-02-06T01:52:15.309596Z",
     "start_time": "2025-02-06T01:52:15.305092Z"
    }
   },
   "source": [
    "from typing import List\n",
    "\n",
    "@dataclass\n",
    "class TransformerEncoderOutput:\n",
    "    last_hidden_states: Tensor\n",
    "    attn_scores: List[Tensor]\n",
    "\n",
    "# https://pytorch.org/docs/stable/generated/torch.nn.Module.html#torch.nn.Module\n",
    "class TransformerEncoder(nn.Module):\n",
    "    def __init__(self, config):\n",
    "        super().__init__()\n",
    "        # hyper params\n",
    "        self.num_layers = config[\"num_encoder_layers\"]\n",
    "\n",
    "        # layers,仅仅是一个模块的列表，它本身没有定义前向传递（forward pass）过程。你需要在 forward 方法中明确地定义如何使用这些模块。\n",
    "        self.layers = nn.ModuleList(\n",
    "            [TransformerBlock(config) for _ in range(self.num_layers)]\n",
    "        )\n",
    "\n",
    "    def forward(\n",
    "        self, encoder_inputs_embeds, attn_mask=None\n",
    "    ) -> TransformerEncoderOutput:\n",
    "        attn_scores = [] # 存储每个层的注意力分数\n",
    "        embeds = encoder_inputs_embeds # 输入的嵌入向量作为第一层的输入(embedding+位置编码)\n",
    "        for layer in self.layers:\n",
    "            block_outputs = layer(embeds, attn_mask=attn_mask)\n",
    "            embeds = block_outputs.hidden_states #上一层的输出作为下一层的输入\n",
    "            # 在每个层的输出中，提取了隐藏状态 block_outputs.hidden_states，并将对应的注意力分数 block_outputs.self_attn_scores 添加到列表 attn_scores 中。\n",
    "            attn_scores.append(block_outputs.self_attn_scores) # 存储每个层的注意力分数,用于画图\n",
    "\n",
    "        return TransformerEncoderOutput(\n",
    "            last_hidden_states=embeds, attn_scores=attn_scores\n",
    "        )\n",
    "\n"
   ],
   "outputs": [],
   "execution_count": 31
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "BEMNj6eBN4yE"
   },
   "source": [
    "#### Decoder"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "wCHOur-QN4yE",
    "ExecuteTime": {
     "end_time": "2025-02-06T01:57:14.347152Z",
     "start_time": "2025-02-06T01:57:14.343465Z"
    }
   },
   "source": [
    "@dataclass\n",
    "class TransformerDecoderOutput:\n",
    "    last_hidden_states: Tensor\n",
    "    self_attn_scores: List[Tensor]\n",
    "    cross_attn_scores: List[Tensor]\n",
    "\n",
    "\n",
    "class TransformerDecoder(nn.Module):\n",
    "    def __init__(self, config):\n",
    "        super().__init__()\n",
    "        # hyper params\n",
    "        self.num_layers = config[\"num_decoder_layers\"]\n",
    "\n",
    "        # layers\n",
    "        self.layers = nn.ModuleList(\n",
    "            [\n",
    "                TransformerBlock(config, add_cross_attention=True)\n",
    "                for _ in range(self.num_layers)\n",
    "            ]\n",
    "        )\n",
    "\n",
    "    def forward(\n",
    "        self,\n",
    "        decoder_inputs_embeds,\n",
    "        encoder_outputs,\n",
    "        attn_mask=None,\n",
    "        cross_attn_mask=None,\n",
    "    ) -> TransformerDecoderOutput:\n",
    "        self_attn_scores = [] # 存储每个层的自注意力分数\n",
    "        cross_attn_scores = [] # 存储每个层的交叉注意力分数\n",
    "        embeds = decoder_inputs_embeds # 输入的嵌入向量作为第一层的输入(embedding+位置编码)\n",
    "        for layer in self.layers:\n",
    "            block_outputs = layer(\n",
    "                embeds,\n",
    "                attn_mask=attn_mask, # 自注意力的mask\n",
    "                encoder_outputs=encoder_outputs,\n",
    "                cross_attn_mask=cross_attn_mask, # 交叉注意力的mask\n",
    "            )\n",
    "            embeds = block_outputs.hidden_states # 上一层的输出作为下一层的输入\n",
    "            self_attn_scores.append(block_outputs.self_attn_scores) # 存储每个层的自注意力分数,为了画图\n",
    "            cross_attn_scores.append(block_outputs.cross_attn_scores) # 存储每个层的交叉注意力分数，为了画图\n",
    "\n",
    "        return TransformerDecoderOutput(\n",
    "            last_hidden_states=embeds,\n",
    "            self_attn_scores=self_attn_scores,\n",
    "            cross_attn_scores=cross_attn_scores,\n",
    "        )\n"
   ],
   "outputs": [],
   "execution_count": 32
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "zPrvXAXtN4yF"
   },
   "source": [
    "#### mask\n",
    "\n",
    "- mask实际上大类上只有两种\n",
    "    1. `padding_mask`：mask掉`pad_idx`，不计算损失\n",
    "    2. `attention_mask`：mask掉`pad_idx`，不计算注意力分数\n",
    "- Decoder的`attention_mask`和Encoder有一定的区别：\n",
    "    - Encoder可以同时看见序列所有信息，故只mask掉`pad_idx`\n",
    "    - Decoder只能看到在自身之前的序列的信息，故要额外mask掉自身之后的序列"
   ]
  },
  {
   "cell_type": "code",
   "source": "(torch.triu(torch.ones(5, 5))==0).transpose(-1, -2)",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "D2N9VmcAWLn1",
    "outputId": "560b8af9-c854-4fd7-df3e-86e9eb9045cc",
    "ExecuteTime": {
     "end_time": "2025-02-06T02:28:06.090352Z",
     "start_time": "2025-02-06T02:28:06.085850Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[False,  True,  True,  True,  True],\n",
       "        [False, False,  True,  True,  True],\n",
       "        [False, False, False,  True,  True],\n",
       "        [False, False, False, False,  True],\n",
       "        [False, False, False, False, False]])"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 38
  },
  {
   "cell_type": "code",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 426
    },
    "id": "QxpSYOsaN4yF",
    "outputId": "1022d3c3-c72e-4798-b998-c71c6690b94e",
    "ExecuteTime": {
     "end_time": "2025-02-06T02:23:11.141381Z",
     "start_time": "2025-02-06T02:23:11.067279Z"
    }
   },
   "source": [
    "\n",
    "def generate_square_subsequent_mask(sz: int) -> Tensor:\n",
    "    \"\"\"\n",
    "    Generate a square mask for the sequence. The masked positions are filled with True.\n",
    "        Unmasked positions are filled with False.\n",
    "    \"\"\"\n",
    "    # torch.ones(sz, sz): 创建一个全为 1 的 sz × sz 的矩阵。\n",
    "    # torch.triu(...): 使用 triu 函数取得矩阵的上三角部分，将主对角线以下部分置零。\n",
    "    mask = (torch.triu(torch.ones(sz, sz)) == 0).transpose(-1, -2).bool()\n",
    "    # mask = torch.triu(torch.ones(sz, sz))\n",
    "    return mask\n",
    "\n",
    "\n",
    "plt.matshow(generate_square_subsequent_mask(16)) #画出一个16×16的矩阵热力图，黄色部分为True，是掩码\n",
    "plt.colorbar()\n",
    "plt.xlabel(\"keys\")\n",
    "plt.ylabel(\"querys\")\n",
    "plt.title(\"1 means mask while 0 means unmask\")\n",
    "plt.show()"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 480x480 with 2 Axes>"
      ],
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAbEAAAGZCAYAAAAHLw/qAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAPZxJREFUeJzt3Q2cTPX+B/DvLHbX89PmYVmRRB7X0wop5WHrulLqhoRLkSK0EluxSiwllyKipG6JbiFJJBHCXQ/pcvNYWE+LvdWuh2uXnfN/fX63mf/M7OzuzM6xc86Zz/u+zs2cnTnzm5kz8z2/3+/7+/1smqZpQkREZEJhwS4AERFRYTGIERGRaTGIERGRaTGIERGRaTGIERGRaTGIERGRaTGIERGRaTGIERGRaTGIERGRaTGIUdAsWrRIbDab7Ny5s8ies2PHjtK4ceMC73fs2DFVNpTRYeLEiWof0fXiOMfS09ODXRTTMHUQu3jxoiQlJck999wjlSpVyvWjQ2R0WVlZMnbsWImOjpaSJUtKmzZtZN26dcEuFpFpmDqI4Wrl5Zdflv3790uzZs2CXRyykBtvvFH++9//Sr9+/a7r8/z1r3+VGTNmSN++fWXWrFlSrFgx+dOf/iRbtmy5rs9LZBXFxcSqV68uZ86ckWrVqqkmqdatWwe7SGQRqNVHRkZe1+dISUmRJUuWyGuvvSbPPvus2te/f3/V3Pncc8/J1q1br+vzE1mBqWtiERERKoAFchVcpkwZSU1NlT//+c/q3zVq1JA5c+aov+/du1fuvvtuKV26tLoyX7x4ca5j/P777zJq1CiJiYlR5bn55ptl2rRpYrfb3e43ffp0adeunVSuXFk1G7Vs2VI+/fRTrz+ew4cPlxUrVqgfMxyzUaNGsmbNGrf7XbhwQT1v7dq11X2qVKkiXbp0kd27d/vU5n7o0CF59NFHpXz58nLDDTfI+PHjBQsanDhxQnr06CHlypVT7+3rr7/u9vjs7GyZMGGCKj8ei/emQ4cOsmHDhlzPhR9o3K9s2bLqeE2aNFG1jfz89ttvEhcXJzVr1pSDBw96vQ/ec9RY3njjDbdaeVhYmHp/XRdmePLJJ72eIz/99JPcddddUqpUKfWZv/rqqwX2ieXlww8/VK8TnyuatXv37q3ex4Lg88frGDJkiHMfAudjjz0m27ZtK/AYjv69f/3rX3LnnXeq14Lzz3Fefffdd6p5EuWqX7++fPPNN7mOcerUKRk0aJBUrVrVea4tXLiwUJ+54z3DuT5//nypW7euOiYuLnfs2OF237S0NBk4cKD6nHEfXJDivMMxCnrN2Lx9l/FdKExZAv0d+PXXX9VFCM5vPBbn+r333is//vhjrnK++eab6j3GZ1WxYkVp1aqV198VV8ePH1efKz7rs2fPilFt2rRJunfvrprG8d7jN6wgGzdulBYtWjh/OwvTHWTqIKaHnJwcdcIhCOGHDF8EBBG8mehrw0mGoIQfYlwlHz161PnYy5cvqx8P/Ijhb/hRbd++vSQmJkpCQoLb8+DHu3nz5qr5c8qUKVK8eHH5y1/+Il9++WWuMqEp6amnnlI/hijTlStX5MEHH5T//Oc/zvsMHTpU5s6dq/a/9dZb6kuEHys0rfqiV69eKtBOnTpV/dC98sorMnPmTBUI8QXGa8ZJhePi5HTIzMyUd955R/2Q4D4IiufPn5f4+HjZs2eP837o1+nTp4/6ouJ+eB485vvvv8+zTAhE+LHAFxU/wPjh9aZChQrqC+1aLrxn+OLgBwUBymHz5s3qB9czUOKzRRM0gnSDBg1Uv9RXX30l/po8ebL67OvVq6eaBXFhsX79ernjjjtUsM3PDz/8ILfccov60XOFIA6u72de8Frww4vPEOcKfgxw3ixdulT9F02TeO8vXbokDz30kLr4ccD7fNttt6nghnMe5yg+cwRRnAv+fuYO+FFG7fKJJ55Q5xUCSs+ePeXq1avO++C8Xb58uQpkOH9HjBihyoZAoidfyhLo78Avv/yifrDxOeAcGDNmjAp8+G04ffq0834LFixQr7Nhw4bq/X3ppZckNjZW/vnPf+ZZ/p9//lmdS3he/ODjYsOoLl26pL5TjuBfELyH3bp1UxeTOI/w3Xn88cdl7dq1/j2xZhE7duzA5bf23nvv+fyYAQMGqMdMmTLFue+3337TSpYsqdlsNm3JkiXO/QcOHFD3TUpKcu6bNGmSVrp0ae3QoUNuxx03bpxWrFgxLTU11bnv8uXLbvfJzs7WGjdurN19991u+/Ec4eHh2pEjR5z7fvzxR7X/zTffdO4rX768NmzYMM1fKD+ONWTIEOe+a9euaTVr1lSveerUqbneC7xPrvfNyspyOybuV7VqVW3QoEHOfSNHjtTKlSun7p8XfFYoCz67M2fOaI0aNdJuuukm7dixYwW+Drx2PKdDQkKCdscdd2hVqlTR5s6dq/b95z//Ua9p1qxZzvvdeeed6jk/+OAD5z68nmrVqmkPPvigc9/Ro0dznU+O984B5cTnPHnyZLey7d27VytevHiu/Z7wej0/f/j3v/+tnmfevHn5Pt7xWhYvXpzrPA0LC9O2b9/u3L927dpcr+exxx7TqlevrqWnp7sdt3fv3ur8cpyzvn7mjvescuXK2q+//urc//nnn6v9X3zxhfOxuP3aa6/l+/ryes3YPOEcvfHGG/0uix6/A1euXNFycnLcyoPnj4iI0F5++WXnvh49eqjPPD+Oc+z8+fPa/v37tejoaK1169Zur8EMRERbvnx5vvd57rnncr0fvXr10uLj4/16rpCviQGiv+tVPmoAaDp4+OGHnfuxD3/DVZfDP/7xD3WVj9oGahGOrXPnzurKzrWmgFqS69VzRkaGeqy35j88Hs0fDk2bNlVX667PjbLgCs71Sq+wrxlNWrjSxLmHq3DP98L1eXHf8PBw9W/U5FDzuXbtmnq862vBY3Fl5kum3cmTJ9VVK66O8Z6hyaYgeO9Qk3A0OaLGhStW7Me/HbUzvCbPmhiafNCU6oDXg9qP6+v0xbJly9R7gPPE9fNH8yVqZt6aWF0hcQQ1J0+Ovjj8vSB4LahxeZ6nt956q6qdOTj+7XiNeF8+++wz1fyDf7uWHzUsnJ+Oz9PXz9y1lo/vhIPj/Xc8N74LOB5qFvguXE8FlUWP3wF8hmjKBnzv0WKCzwX39fxO4Fz3bM70Zt++feo7gRohasqur8Eqtm3bpn7rXOHcw/6QSezQA34w0CfkCu3+aKv3HBOE/a5fusOHD6v+CM/HO5w7d87571WrVqnmDFSbkVbt4G3cUa1atXLtw0ns+txo8hgwYIBq/kBfBZqN0Mxx0003+fS6PZ8Drw3vRVRUVK79rs2Y8P7776tmuAMHDrg1y9SpU8f5bzSHfvLJJ6qJBs2TXbt2VT8GaJrxhAxANK+iKdTXPk7HjxECFj4rNM3h/cVngX4Qx98Q/D0zV719tnh/8Vn6A58/AgACljclSpTI9/H4MXc9FxzQfOz4e0HyOk9xXnjuA8c5hOZANHeivwhbQeevL595XueW4wfY8dz40UfT3OjRo1XzGJo00RSH8zeQPm5vCiqLHr8DCOxoikWzKJrIEMgc0EfrgCZrBCRcMKHZFt+JRx55RHVBeMLFBd4bNK0hIPrjypUrqh9TDzi/PV8/Pj9vF1/+Qr+oZ/MobqP5Ghdwvpz/EPJBDFeZ/ux3TRrAyYs+JGSSeYP+DseP6X333adqCjjR0YmNH7j33nvPa6euL8+NgIAfcvQrfP3116rdHz8MqB0gcBTE23P48rzo/0NH+P3336/a/pFQgsclJyer9nsH7EfAxpcQfU3Y8HrxQ4UfRFfoo/jggw/UDwGO4wt0HuMHFDU3XK2ijG3btlU/RCNHjlSd4XjfkUzjuEr253X6Ap8/vuB4bd6OWdCPD84DJFZ4Qsat4zVer/PXkXiEGikuhrxBC4A/n7mvzw3o/8APNfqScI4gsQjH+/bbb1XfcV7wfnv7nFwDh79lye9+vjwefdwoPxJkJk2apJJ7cM7hNbomeKF2jJYDXNAiUQs1YfweIGkG/WOu0GeI78lHH32k+vP8CWB1biwjaee8vx/+wjmM8biuMDYX/aJGEfJBLBBo8sMH7Fkl9oSTFVd6+LK6XsHgRz0Q+BFEjQcbrpqR5YNEA1+CWGEh8w21PQRL1ys0nNie0GSEHyps+DKjnG+//bb6wuNK1OHpp59Wt/FlxlXuuHHjfCoLgjiCGIIZOsjR+Y1aF46BHwk05Xj+OOj9+ePHDM/vuGDxB8qMJkdcebomdzg6+vH36wXBHu8XfvwLOn/9+cz9ff9QG8OGWi1eL2p7CJp5QU3KW1MgLlqCBe8PkhPeffddt/2o6Xq2bKB5Ek2c2FBbwgUcvrNIBnMd0oGLUrRO4DuDzwk1Nl9kZ2erAHZ0141SrmxgvUWZF+xSp+VxlSXren7qUQsD1Lo9sy1xG8/lay0M2CcWANSG0H7rLZsGJzD6DRxXc/jyu14tIkvKlxRUb3Ac9Fm4wtUxrty9NU/pyXFl6nolih9dz3ZszyZIXJk6ruy9lRGBDZmQ+DIj69LXIIb3EZl4juZFPA9qX8gSQ7OXZ3+YnvADhPcDgdLzyh63Pd8DT8gWxGfp2pyH9wYXN+jD8mwS1BPKjat9XGCh/8UTmhtd7+vLZ+4rZPU6mkxdAxp+rAs6f3E/NGm6lg+p7PllvV5veH88P3/0l3vWsj3PB1zkIVMRj/XMlsTvBc4LnCOoKa9cudKvMpUuo88GCCqum15BDC0nyOR1hT507A+pmtjs2bNVwHAkOHzxxReq89Rxhe/oC7ge0LSCkwvt+WhuQd8UkhmQXourM/zA4koMaaT4UUV/EK6oUGtCGipqH/72wwBSkdFWjxMcNQ9U+dHWjg5jz3FdesNrxRX5Aw88oF4X+gDmzZunvoyuzQ7oJEcCAFLmUVZcKWOMDK620aziDa4+EZyHDRumftBcky+8cQQoNNGgSccBzbZo4nOMC7pe8IOKfjgEXnzWaG5DufGeoJkX478cg5i9QaDCMAs8HucEzgc0IeFYnlf11wNS71ETRDkGDx6sPkN8ZqjB4nzCv/35zH2FMYqdOnVSF4E4BmoceL9wFe6apOINmuzwXUICAJKQ8L6hLBh7hRptMOD9wdAZDBfABRS+/2gG9OyfRh8Yah/oA0PfD/qA8fuF9xTnjSdckKFWivMK79Xq1avV98moLl68KEeOHHHexnmCLgU0r6JvEuc5Aju6DhzDhPD60R2DzxVNyehH9zbsKF+aySGtFi/D24Y01/wgtRYp8p6QwustFRbP1a1bN7d9Fy5c0BITE7Wbb75ZpcZHRUVp7dq106ZPn67S6B3effddrV69eirttkGDBirV2TNlG3DbW+o8ntuR6o505zFjxmjNmjXTypYtq14D/v3WW28V+H65pvAW5r2w2+0qFRnlwWtp3ry5tmrVqlwpzp9++qnWtWtXlfKO96VWrVraE088oVLpvaXYOyBVuU+fPipFfcWKFQW+Hhwfxzh79qxz35YtW9S+Dh06FPh6CkrRzi/F3uGzzz7Tbr/9dvX+YcPni8/w4MGDBZb/v//9r/bss8+qFH+8n0inXrNmTYGP8/c8zevcwvuGfTExMVqJEiVUOTp16qTNnz/f78/c8Z55S513TUtHSj+eE+8T3i+k87dp00b75JNPfHrdH374oRqKgfMqNjZWDR8obFn0+B1Aiv3o0aPVcAWk5bdv317btm1bruEAb7/9thoGgrR/vI9169ZV3+OMjIx8v58Y6oDjlClTxm3YhDcZGRnq8WkHa2mXT9cOaMMxcCzX8uVnw4YNXn+HHb9b+K/n8Ag8Bp8hPkt8pv4MkXKw4f/0jshERFT0MjMzVevT6YM1dekTi65/UrWOeA7INxL2iRERkWmZvk+MiIjc5Wia2gIR6OOLCoMYEZHF2EVTW6DHMAM2JxIRkWmxJkZEZDF20SQnRGpiDGJERBZjZ3MiERGR8bEmRkRkMTkhlJ3ImpiImgIKM6FjAk5MwZOSkhK0smAmb0yVhGloMB8ippxxrJllFJiuCHO7YZbuYMIUNpiaCstdYMJQLA+/c+fOoJYJcyFiHkhMCowyYWoqzGxelHMKFLRMPMqCyZYxgTTKiAmAMQFvsMqEeQOxTAk+P0yQi/tgtYPCrpWnR5k8YYok3Md1xWsjs+u0mUHIBzFMHpuQkKBm5MaccZiLEPOyua6lVJS+++47NXfg9u3b1WSY+IJjzjXMyWgEmJ8RM9E7JvMNFqznhDnosKQN5kn86aef1LyRwV48EMvhYAJjzAmHufFwG2u/Yd5IoywTj/K88cYbas5BTOSLwIFz3nNS3qIqEyYExncPwR//xTyNuHDD8kXBfJ8cMK8jvo++LI1jFDl/JHYEupmCFuLi4uLc5pPD3H1YEjw5OVkzgnPnzqn5x7777rtgF0XNE4n5H9etW6fmQBs5cmTQyjJ27Fg1X6HRYE69QYMGue3r2bOn1rdvX0MsE495EDE/ouucgr///ruay+/jjz8OSpm8SUlJUfc7fvx4UMt08uRJrUaNGtq+ffvUnIl/+9vfNCPL+GPuxH/vr6KlnqwW0IZj+DN3YrCEdE0Ma+/s2rXLbT0lzByN24VdZkJvjiVXMBN0sKGGiBm3C1p/qihg9YBWrVqpWeDR7IqFFBcsWBDsYqlZzLG8BGZqdywTsmXLluu6xps/MLM4VtR1/Qwx1x6a0Y1yzjvOezTfVahQIWhlwBp4WHUcq1VglnwzydH02cwgpBM70tPTVR+GtyWysWZRsOFLhH4nNJs1btw4qGVZsmSJaupBc6IRYGFENNuhKfj5559X5RoxYoRaoymvlYqLAhb0xCSsDRo0UOtM4fzCood9+/YVI0AAA2/nvONvwYZmTfSR9enTJ6gTz6IpGMvE4LwyG7sOfVpm6RML6SBmdKj5YMFCXMkHE1Z2HTlypOqjc119NtgBHjUxxzpiqInhvUI/TzCDGNZDwlpSixcvVlfvWE8JFyLoTwlmucwCfcBYOwstfL4ujno9oIVm1qxZ6sLNdTVrMp6Qbk7EgpW4Wva2RDYWrwum4cOHy6pVq9SihVhUMpjwhUaiS4sWLdSVKTYkoCA5AP92XbG6qCCzDgsqusJim6mpqRJMaHpCbQyLOyLbDs1RzzzzjMo6NQLHeW3Ec94RwLCAKi6YglkL27x5szrnsZij45xHuUaPHq0ymY3OLjbJCXDDMcwgpIMYmp6wGrPrEtm4wsdtf5fI1guuQBHAkBGFlU6Rqh1sWIUXq9WiVuHYUAtCExn+7Vi+viihidVz6AH6oW688UYJJmTaoV/VFd4fnFdGgPMJwcr1nEfzJ7IUg3XOuwYwpPpjVWkMmwgmXHxg1XXXcx61aVykrF27VozOrumzmUHINyeiTwXNPPhRjouLU+NAkHqLpcaD1YSIpqjPP/9cjRVz9FOg8x1jeoIB5fDsk0NaNn5ogtVXh9oNkijQnIgfP4ztmz9/vtqCCeOO0AeGK3g0J/7www8yY8YMtfy6UZaJR/PmK6+8IvXq1VNBDant+IHGmMRglAm16oceekg13aH1ATV7x3mPv+NiMxjvk2cgxXAOXADUr1//upSHCinY6ZFG8Oabb2q1atVSS2Qj5b6gJcCvJ2/Le2MrzLLd11OwU+zhiy++0Bo3bqzSw7HU/fz587Vgy8zMVO8LzqfIyEi15PoLL7ygZWVlFVkZClomHmn248eP16pWrareu06dOmkHDx4MWpmOHj2a53mPxwWjTN6YKcX+n/+upv07NTqgDccwQ4q9Df9X2ABIRETGkZmZqVpttv67upQpG1hv0cULdmnX6Iwa7hDM/smChHSfGBERmVvI94kREVmNXbOpLdBjmAGDGBGRxeT8kSYf6DHMgM2JRERkWqyJERFZTI6EqS2wY5gDgxgRkcVoOvSJ4RhmwCBGRGQxOewTCy1ZWVkyceJE9V+jMGKZjFoulsk3LJP5y0W5cbCzywBBIw3qM2KZjFoulsk3LJP5y+Vrub/6Vx0pHeBg50sX7HJv06OGfw/YnEhEZDF2NQt9YEHMrmbhMj42JxIRkWlZviaGJTBOnz6tZmLPa3E7VMFd/2sERiyTUcvFMvmGZTJuudCrc+HCBbWagOdSPoWRE0KJHZbvEzt58qTExMQEuxhERD6toh7IIriZf/SJLf+xnpQuG9g6f5cu5MgDzQ6zTyzYUAOD2+VPUlxKBHy85Yf26lAqIqL/l3nRLje2OOb8vSLfWT6IOZoQEcCK2wIPYuUCzPghIspLXl0ehUvssAV8DDOwfBAjIgo1dh2mnWJ2IhER0XVmiiA2Z84cqV27tkRGRkqbNm0kJSUl2EUiIjKsHC1Ml80MDF/KpUuXSkJCgiQlJcnu3bulWbNmEh8fL+fOnQt20YiIDNucaNdhMwPDl3LGjBkyePBgGThwoDRs2FDmzZsnpUqVkoULFwa7aEREFGSGTuzIzs6WXbt2SWJionMfBgJ27txZtm3b5vUxmLDTddJOow2iJCK63nI0m9oCPYYZGLomlp6eLjk5OVK1alW3/bidlpbm9THJyclqsJ9j40BnIgrVRTFzAtzMwByl9ANqbRhh7tgwAp6IKJTYtTBdNjMwdHNiVFSUFCtWTM6ePeu2H7erVavm9TERERFqIyIi6zN0qA0PD5eWLVvK+vXr3Sb0xe22bdsGtWxEREaVE0LNiYauiQHS6wcMGCCtWrWSuLg4mTlzply6dEllKxIRUW52HRIzcAwzMHwQ69Wrl5w/f14mTJigkjliY2NlzZo1uZI9iIgo9Bg+iMHw4cPVRkREBbPrMFjZLIOdTRHEiIjIdzk6TBvFaaeIiIiuM9bE/BQfHavLcdae3qPLcYiIPHE9MSIiMq0cNicSEREZH2tiREQWk6PDYGUOdiYioqCwaza1BXoMMzBHqCUiIvKCNTEiIoux69CcyMHOREQUFHYdllLhUixERBQUOWJTW6DHMANzhFoiIiIvWBMjIrIYO5sTiYjIrHJ0aA7EMczAHKGWiIjIC9bEiIgsxs7mRCIiMqscTgBMRETknzlz5kjt2rUlMjJS2rRpIykpKfnef+bMmVK/fn0pWbKkxMTEyDPPPCNXrlzx6zkZxIiILEb7Yz2xQDYcwx9Lly6VhIQESUpKkt27d0uzZs0kPj5ezp075/X+ixcvlnHjxqn779+/X9599111jOeff96v52UQIyKyaHNiToCbP2bMmCGDBw+WgQMHSsOGDWXevHlSqlQpWbhwodf7b926Vdq3by+PPPKIqr117dpV+vTpU2DtzRP7xEy+QjRwlWgiul4yMzPdbkdERKjNVXZ2tuzatUsSExOd+8LCwqRz586ybds2r8dt166dfPjhhypoxcXFyS+//CKrV6+Wfv36+VU+BjEiIoux67gUC/qqXKH5b+LEiW770tPTJScnR6pWreq2H7cPHDjg9fiogeFxt99+u2iaJteuXZOhQ4f63ZzIIEZEZDE5Oi6KeeLECSlXrpxzv2ctrLA2btwoU6ZMkbfeekslgRw5ckRGjhwpkyZNkvHjx/t8HAYxIiLKEwKYaxDzJioqSooVKyZnz55124/b1apV8/oYBCo0HT7++OPqdpMmTeTSpUsyZMgQeeGFF1RzpC+Y2EFEZNHmRHuAm6/Cw8OlZcuWsn79+v8vg92ubrdt29brYy5fvpwrUCEQApoXfcWaGBGRxdglLOBFLf19PNLrBwwYIK1atVKJGhgDhpoVshWhf//+UqNGDUlOTla3u3fvrjIamzdv7mxORO0M+x3BzPRBDC922bJlqmMQg+GQzTJt2jQ1OI6IiLzL0WxqC4S/j+/Vq5ecP39eJkyYIGlpaRIbGytr1qxxJnukpqa61bxefPFFsdls6r+nTp2SG264QQWwyZMn+/W8Ns2felsRu+eee6R3797SunVrlbmCrJV9+/bJTz/9JKVLl/Y5PbR8+fLSUXpIcVsJsSKm2BOZW+YFu1S85RfJyMgosP/Jl9+7Jzf3lIgygf3eZV28KnM7LAu4TNeboWtiiOKuFi1aJFWqVFHjEe64446glYuIKFRS7I3O0EHME64IoFKlSnneJysrS215DdQjIrI6TYdZ7HEMMzBHKf/IdBk1apSapqRx48b59qOhOu3YPAfqERGRdZgmiA0bNkz1hy1ZsiTf+2HaE9TYHBsG6hERhZIcsemymYEpmhOHDx8uq1atkk2bNknNmjXzva+3eb2IiEKJXQu8TwvHMANDBzEkTj799NOyfPlyNUVJnTp1gl0kIiIykOJGb0LEmjOff/65lC1bVo09APR1YdwYERHlZtchsSPQxxcVQ5dy7ty5ql+rY8eOUr16deeGhdOIiMi7QBfEdGxmYOiamIHHYRMRkQEYOogREZE5pp0KFgYxIiKLsYdQnxiDmAXER8fqchzOwUhEZsMgRkRkMXYkZgQ6ToyJHUREFAyaDtmFOIYZMIgREVmMPYRmsTdHzx0REZEXrIkREVmMndmJRERkVnY2JxIRERkfa2JERBZj1yE7kSn2REQUFHY2JxIRERkfa2JERBZjD6GaGIMYEZHF2EMoiLE5kYiITIs1MSIii7GHUE2MQYyIyGI0HVLkcQwzYBAjIrIYewjVxNgnRkREpsWaGOm+QjRwlWii4LGHUE2MQYyIyGLsIRTE2JxIRESmxZoYEZHF2EOoJsYgRkRkMZpmU1ugxzADNicSEZFpmSqITZ06VWw2m4waNSrYRSEiMvx6YvYANzMwTXPijh075O2335amTZsGuyhERIZmD6E+MVPUxC5evCh9+/aVBQsWSMWKFYNdHCIiMghTBLFhw4ZJt27dpHPnzgXeNysrSzIzM902IqJQTOzQAtzMwPDNiUuWLJHdu3er5kRfJCcny0svvXTdy0VEZFR2Nicaw4kTJ2TkyJHy0UcfSWRkpE+PSUxMlIyMDOeGYxARkTUZuia2a9cuOXfunLRo0cK5LycnRzZt2iSzZ89WTYfFihVze0xERITaiIhClRZC48QMHcQ6deoke/fudds3cOBAadCggYwdOzZXACMiIlEBKNDmQAYxHZQtW1YaN27stq906dJSuXLlXPuJiOj/F7TUAlzV0iyLYhq6T4yIiMi0NTFvNm7cGOwiEBEZml1s6n+BHsMMTBfEiIgof1oIJXawOZGIiEyLNTG6LuKjY3U71trTe3Q7FlEosGs2sYXIYGcGMSIii9E0HbITTZKeyOZEIiIyLdbEiIgsRguhxA4GMSIii9FCKIixOZGIiEyLNTEiIouxMzuRiIjMSmN2IhERkfGxJkZEZMmamC3gY5gBgxgRkcVoIZSdyCBGRGTF9cQk8GOYAfvEiIjItFgTIyKyGI3NiUREZFpa6LQnsjmRiIh0MWfOHKldu7ZERkZKmzZtJCUlJd/7//777zJs2DCpXr26REREyC233CKrV6/26zlZEyMishot8OZEHMMfS5culYSEBJk3b54KYDNnzpT4+Hg5ePCgVKlSJdf9s7OzpUuXLupvn376qdSoUUOOHz8uFSpU8Ot5GcSIiCxGC8KMHTNmzJDBgwfLwIED1W0Esy+//FIWLlwo48aNy3V/7P/1119l69atUqJECbUPtTh/sTmRiIjylJmZ6bZlZWV5rVXt2rVLOnfu7NwXFhambm/bts3rcVeuXClt27ZVzYlVq1aVxo0by5QpUyQnJ0f8wZoYGV58dKwux1l7eo8uxyEKpezEmJgYt/1JSUkyceJEt33p6ekq+CAYucLtAwcOeD3+L7/8It9++6307dtX9YMdOXJEnnrqKbl69ap6Dl8xiBERWY1m87tPy+sxROTEiRNSrlw5524kYOjBbrer/rD58+dLsWLFpGXLlnLq1Cl57bXXGMSIiEgfCGCuQcybqKgoFYjOnj3rth+3q1Wr5vUxyEhEXxge53DrrbdKWlqaap4MDw/3qXzsEyMismhihxbg5isEHNSk1q9f71bTwm30e3nTvn171YSI+zkcOnRIBTdfAxgwiBERWXWwsxbg5gek1y9YsEDef/992b9/vzz55JNy6dIlZ7Zi//79JTEx0Xl//B3ZiSNHjlTBC5mMSOxAooc/DB/E0Eb66KOPSuXKlaVkyZLSpEkT2blzZ7CLRURELnr16iXTp0+XCRMmSGxsrOzZs0fWrFnjTPZITU2VM2fOOO+PhJG1a9fKjh07pGnTpjJixAgV0Lyl45u2T+y3335TVc677rpLvvrqK7nhhhvk8OHDUrFixWAXjYjIsLQgzZ04fPhwtXmzcePGXPvQ1Lh9+3YJhKGD2LRp01S0fu+995z76tSpE9QyERGZgiYhwdDNiRgM16pVK/nLX/6iUjGbN2+u2lyJiChvjppYoJsZGDqIYTDc3LlzpV69eqrtFB2BaDdFx2FeMJrcc4Q5ERFZk6GbE5F6iZoYMlYANbF9+/apObkGDBjg9THJycny0ksvFXFJiYgMRONSLIaA8QINGzZ024fBcMhyyQtSODMyMpwbRpsTEYUWm06b8Rm6JobMREzj7wrjCW688cY8H4MpUfSaFoWIiIzN0DWxZ555RqVfojkRI7sXL16s5tnydzAcEVFI0Yp+sHOwGDqItW7dWpYvXy4ff/yxmqZ/0qRJaqE1zHpMRER5CKEgZujmRPjzn/+sNiIiIl1qYkiWOHnypPN2SkqKjBo1SjX1ERGRQZZi0QLcrBrEHnnkEdmwYYP6N6bN79KliwpkL7zwgrz88st6l5GIiAw8i73pmhMxVisuLk79+5NPPlH9Vd9//718/fXXMnToUDUBJJFVV4gGrhJNZOIghuWjHWns33zzjdx3333q3w0aNHCbpZiIiIJA42DnfDVq1EjNmrF582ZZt26d3HPPPWr/6dOn1ZIpREQURBr7xAqcXf7tt9+Wjh07Sp8+faRZs2bOCXsdzYxERESGbE5E8EpPT1eT67qu7TVkyBApVaqUnuUjIiI/2bT/bYEew7I1saSkJJVi77k4Ze3atdWSKUREFERa6Ax2LlQQ+/zzz6Vu3brSqVMnNRUUlj8hIiKD0Ngnlq89e/bIjh07VILHyJEjpVq1amqtL+wjIiIy/NyJWNvrjTfeUBmJ7777rmpexKzzTZs2lVmzZqllUIiIKAg0Nif6TNM0NW4sOztb/Rv9ZLNnz5aYmBhZunSpPqUkIiLfaQxiBdq1a5cMHz5cLVyJJVNQM9u/f7989913cvjwYZk8ebKMGDFC39ISEREFGsSaNGkit912mxw9elQ1JWJC4KlTp8rNN9/svA/Gj50/f74whyciokBooVMTK9Q4sYcfflgGDRokNWrUyPM+UVFRYrfbAykbEREVhqZDdqFVsxPR/7Vo0SI10JmIiMhUNbESJUrIlStXrk9piIgoYDbO2JG/YcOGqfkTr127pn+JiIgoMBr7xPKFQc3r169X64chyaN06dJuf1+2bJle5SMiItI3iFWoUEEefPDBwjyUiIgouEHsvffe068ERESkK5sOfVo2KwcxQH/Yxo0b5eeff5ZHHnlEypYtq6agKleunJQpU0bfUhIZTHx0rG7HWnt6j27HIgo1hQpix48fV6s5p6amqhnsu3TpooIYkj1wG6s+ExFRkGgcJ5YvzFzfqlUr+e2336RkyZLO/Q888IBK+CAioiDSmJ2Yr82bN8vWrVslPDw816KYp06d0qtsRERUGHoEIZMEsULVxDCdVE5OTq79WI4FzYpERESGDWJdu3aVmTNnOm/bbDa5ePGiJCUlyZ/+9Cc9y0dERIWcscMW4GbZIPb666/L999/Lw0bNlRTUCE70dGUiOQOvaC2N378eKlTp47qe6tbt65MmjRJrVtGRER5YJ9Y/mrWrCk//vijLFmyRP71r3+pWthjjz0mffv2dUv0CBQC4ty5c+X999+XRo0ayc6dO2XgwIFSvnx5rlVGRESFHydWvHhxefTRR+V6QvJIjx49pFu3buo2ansff/yxpKSkXNfnJSIyNS10EjsKFcQ++OCDfP/ev39/0UO7du1k/vz5cujQIbnllltU7W/Lli0yY8aMPB+DcWrYHLhkDBGFGlsIzWJfvLDjxDzXGLt8+bJKuS9VqpRuQWzcuHEqCDVo0ECKFSum+sgmT56smi3zkpycLC+99JIuz09ERBZM7MAgZ9cNfWIHDx6U22+/XTX36eWTTz6Rjz76SBYvXiy7d+9WfWPTp09X/81LYmKiZGRkOLcTJ07oVh4iIlPN2KEFuFm5T8xTvXr1ZOrUqaqf7MCBA7occ8yYMao21rt3b3Uby75gyivUtgYMGOD1MREREWojIgpZWuj0iRWqJpZfsgcmAdYLmijDwtyLiGZFDLYmIiIqVE1s5cqVbrcxbuvMmTMye/Zsad++vV5lk+7du6s+sFq1aqkU+x9++EEldQwaNEi35yAishobEzvyd//997vdxowdN9xwg9x9991qILRe3nzzTTXY+amnnpJz585JdHS0PPHEEzJhwgTdnoOIyHK00GlOLFQQK6rmPMzDiOmtXKe4IiKiAmg61KSsHMQSEhJ8vm9+Y7qIiIiKPIihbwop71jduX79+mofBiQj6aJFixZuzYxERFTENDYnFphwgaY+jNeqWLGi2ofxYpjXsEOHDjJ69Gi9y0lkWfHRsbocZ+3pPbochyxAC50gVuhZ7DFWyxHAAP9+5ZVXdE3sICIi0r0mhqmgzp8/n2s/9l24cKEwhyQiIp3YQijFvlA1sQceeEA1HS5btkyt5ozts88+U8ux9OzZU/9SEhER6VUTmzdvnjz77LNqMUxM/qsOVLy4CmKvvfZaYQ5JRERUNEEMM9W/9dZbKmD9/PPPah9WXS5dunRhDkdERHrSQiexI6AJgBG0mjZtql9piIgoYDb2iREREYXQUixERGQgmoQEBjEiIqvRQqdPjM2JRERkWqyJERFZjC2EEjsYxIiIrEYLneZEBjEiIouxhVBNjH1iRERkWgxiRERWbU7UAtz8NGfOHKldu7ZERkZKmzZtJCUlxafHLVmyRK0/ef/99/v9nAxiRERWoxV9EFu6dKkkJCRIUlKSWjS5WbNmEh8fL+fOncv3cceOHVNz8WItysJgECMiooDNmDFDBg8erFY4adiwoZooHvPsLly4MM/H5OTkSN++feWll16Sm266qVDPy8QOIovQa4Vo4CrR5mbTMbED60e6ioiIUJur7Oxs2bVrlyQmJjr3hYWFSefOnWXbtm15PsfLL78sVapUUSugbN68uVDlZE2MiMhqNP2aE2NiYqR8+fLOLTk5OdfTpaenq1pV1apV3fbjdlpamtcibtmyRd59911ZsGBBQC+VNTEiIsrTiRMnpFy5cs7bnrWwwrhw4YL069dPBbCoqKiAjsUgRkRkNZp+g50RwFyDmDcIRMWKFZOzZ8+67cftatWq5bo/1qFEQkf37t2d++x2u3OB5YMHD6o1Kn3B5kQiIov2idkC3HwVHh4uLVu2lPXr17sFJdxu27Ztrvs3aNBA9u7dK3v27HFu9913n9x1113q32jC9BVrYkREFDCk1w8YMEBatWolcXFxMnPmTLl06ZLKVoT+/ftLjRo1VJ8axpE1btzY7fEVKlRQ//Xcb+ia2KZNm1R1Mjo6Wg10W7FihdvfNU2TCRMmSPXq1aVkyZIq0+Xw4cNBKy8RkSloRT9OrFevXjJ9+nT1mx0bG6tqVGvWrHEme6SmpsqZM2d0f6lBrYkhSmNA3KBBg6Rnz565/v7qq6/KG2+8Ie+//77UqVNHxo8frwbP/fTTTyqSExGRceZOHD58uNq82bhxY76PXbRokfmC2L333qs2b1ALQ3X0xRdflB49eqh9H3zwgYrqqLH17t27iEtLRERGY9jEjqNHj6rxBWhCdMAYBczHld/guaysLDU4z3UjIgopWnDmTgwGwwYxxwA5fwbPAToNXQfm+ZPlQkRkCRqDmGlh2pOMjAznhoF6REShxKbTZgaGDWKOAXK+Dp5zHU3uGJznyyA9IiIyL8MGMWQjIli5Dp5D/9Y///lPr4PniIgo9JoTg5qdePHiRTly5IhbMgfGFlSqVElq1aolo0aNkldeeUXq1avnTLHHmLLCLJxGRBQqbEFKsQ+5ILZz5041zYjriG/AqG+MGXjuuefUWLIhQ4bI77//LrfffrsaPMcxYkREFPQg1rFjRzUeLC+YxQPrzWAjIqKinwDY6Dh3IhGRFWkSEgyb2EFERFQQ1sSIKJf46FhdjrP29B5djkP+sTGxg4iITEsLnT4xNicSEZFpsSZGRGQxNjYnEhGRaWlsTiQiIjI81sSIiCzGxuZEIiIyLS10mhMZxIiIrEYLnSDGPjEiIjIt1sSIiCzGxj4xIiIyLY3NiURERIbHmhgRkcXYNE1tgR7DDBjEiIisRmNzIhERkeGxJkZEZDE2ZicSEZFpaaHTnMggRkSGXyEauEo0ecMgRkRkMTY2JxIRkWlpodOcyOxEIiIyLdbEiIgsxsbmRCIiMi2NzYlFYtOmTdK9e3eJjo4Wm80mK1ascP7t6tWrMnbsWGnSpImULl1a3ad///5y+vTpYBaZiMhUtTFbITezCGoQu3TpkjRr1kzmzJmT62+XL1+W3bt3y/jx49V/ly1bJgcPHpT77rsvKGUlIiLjCWpz4r333qs2b8qXLy/r1q1z2zd79myJi4uT1NRUqVWrVhGVkojIZDTtf1ugxzABU/WJZWRkqGbHChUq5HmfrKwstTlkZmYWUemIiIzBFkKJHaZJsb9y5YrqI+vTp4+UK1cuz/slJyerWpxji4mJKdJyEhFR0TFFEEOSx8MPPyyapsncuXPzvW9iYqKqsTm2EydOFFk5iYgMlZ2oBbiZQHGzBLDjx4/Lt99+m28tDCIiItRGRBSqbPb/bYEewwyKmyGAHT58WDZs2CCVK1cOdpGIiMhAghrELl68KEeOHHHePnr0qOzZs0cqVaok1atXl4ceekil169atUpycnIkLS1N3Q9/Dw8PD2LJiYgMTAudwc5BDWI7d+6Uu+66y3k7ISFB/XfAgAEyceJEWblypbodG+u+nANqZR07dizi0hIRmYMthLITgxrEEIiQrJGX/P5GRERk6D4xIiIqBI2DnYmIyKRsbE4kIjKW+Gj3vvFArD29R7djUXAxiBERWY3G7EQiIjIpG5sTiYjItLTQSewwxdyJRERE3rAmRkRkMTY2JxIRkWlpoZPYweZEIiIyLdbEiIgsxsbmRCIiMi279r8t0GOYAJsTiYjItFgTIyKyGi10EjsYxIiILMamQ58WjmEGbE4kIiLTYk2MiMhqNE47RUREJk+xtwW4+WvOnDlSu3ZtiYyMlDZt2khKSkqe912wYIF06NBBKlasqLbOnTvne/+8MIgREVk1sUMLcPPD0qVLJSEhQZKSkmT37t3SrFkziY+Pl3Pnznm9/8aNG6VPnz6yYcMG2bZtm8TExEjXrl3l1KlTfj0vgxgREQVsxowZMnjwYBk4cKA0bNhQ5s2bJ6VKlZKFCxd6vf9HH30kTz31lMTGxkqDBg3knXfeEbvdLuvXr/freRnEiIgsxqZpumyQmZnptmVlZeV6vuzsbNm1a5dqEnQICwtTt1HL8sXly5fl6tWrUqlSJb9eKxM7iCjkxEfH6nKctaf3iCHZ/9gCPYaIauZzhebCiRMnuu1LT0+XnJwcqVq1qtt+3D5w4IBPTzd27FiJjo52C4S+YBAjIqI8nThxQsqVK+e8HRERIXqbOnWqLFmyRPWTISnEHwxiREQWY3NpDgzkGIAA5hrEvImKipJixYrJ2bNn3fbjdrVq1fJ97PTp01UQ++abb6Rp06Z+l5N9YkREVqMVbXZieHi4tGzZ0i0pw5Gk0bZt2zwf9+qrr8qkSZNkzZo10qpVq0K9VNbEiIgoYEivHzBggApGcXFxMnPmTLl06ZLKVoT+/ftLjRo1JDk5Wd2eNm2aTJgwQRYvXqzGlqWlpan9ZcqUUZspamKbNm2S7t27q848m80mK1asyPO+Q4cOVffBG0NERPlwzNgR6OaHXr16qaZBBCakze/Zs0fVsBzJHqmpqXLmzBnn/efOnauyGh966CGpXr26c8MxTFMTQ5TGgLhBgwZJz54987zf8uXLZfv27SrYERGRMRfFHD58uNq8QdKGq2PHjokeghrE7r33XrXlB6O3n376aVm7dq1069atyMpGRETGZ+g+MXQM9uvXT8aMGSONGjXy6TEYiOc6GA+D84iIQorGCYANAR1/xYsXlxEjRvj8GHQali9f3rl5DtQjIrI6m12fzQwMG8QwhcmsWbNk0aJFKqHDV4mJiZKRkeHcMFCPiIisybBBbPPmzWr241q1aqnaGLbjx4/L6NGjVTpmXjCa3DE4z5dBekRElqMVfXZisBi2Twx9YZ5zaGFaf+x3jDsgIiIvCrGUitdjmEBQg9jFixflyJEjzttHjx5VYwswizFqYJUrV3a7f4kSJdQUJvXr1w9CaYmIQm/aKaMLahDbuXOn3HXXXW4jvgGjvtEXRkREZNgg1rFjR9H8iPZ6DY4jIrI0LXRS7A3bJ0ZERIWk6bCemDlimHGzE4mIiArCmhgRUZBXiL6mXRWRX0QvNiZ2EBGRuVPstcCPYQJsTiQiItNiTYyIyGo0ZicSEZFZ2dGppcMxTIDNiUREZFqsiRERWYyN2YlERGRaWuj0ibE5kYiITIs1MSIiq9FCpybGIEZEZDUagxgREZmVnSn2REREhseaGBGRxdiYYk9ERKalhU6fGJsTiYjItFgTIyKyGruG9sDAj2ECDGJERFajhU5zouWDmPbHB3FNrppmkTciCi3q98nl94p8Z/kgduHCBfXfLbI62EUhIirw96p8+fI6HEnToSZljoBq+SAWHR0tJ06ckLJly4rN5n30X2ZmpsTExKj7lStXTozAiGUyarlYJt+wTMYtF2pgCGD4vdLpgMLmRIsICwuTmjVr+nRfnKxG+iIZtUxGLRfL5BuWyZjl0qcGFnosH8SIiEKOHbUoZicSEZEZafb/bYEewwQ42FlEIiIiJCkpSf3XKIxYJqOWi2XyDctk/nJRbjaNOZ1ERJaQmZmp+tY6xzwpxcMCC8DX7FnyzYm5kpGRYcj+Sgc2JxIRWY2dfWJERGRWWuik2LNPjIiITIs1MSIiq9F0qEmZoyLGmhiFro4dO8qoUaOCXQyi69ecqAW4mQCDGBERmRabE4mIrMaOgcp2HY5hfKyJEf3hyy+/VGNsPvroIzXx68MPPywVKlSQSpUqSY8ePeTYsWPqfps2bZISJUpIWlqa2+PRNNmhQwf17+PHj0v37t2lYsWKUrp0aWnUqJGsXs2VFKiIaGxOJAopixcvlj59+qgAhuAVHx+vVj7YvHmzfP/991KmTBm55557JDs7W+644w656aab5O9//7vz8VevXlWPHTRokLo9bNgwycrKUgFv7969Mm3aNHUMItIXmxMp5M2ZM0deeOEF+eKLL+TOO++UDz/8UOx2u7zzzjvO5Xvee+89VSvbuHGjdO3aVR577DG1b8yYMerveOyVK1dUAITU1FR58MEHpUmTJuo2gh5RkdFCZ5wYgxiFtE8//VTOnTunalutW7dW+3788Uc5cuSIqom5QpD6+eef1b//+te/yosvvijbt2+X2267TRYtWqQCGJoOYcSIEfLkk0/K119/LZ07d1YBrWnTpkF4hRSS7KEzYwebEymkNW/eXG644QZZuHChc2n4ixcvSsuWLWXPnj1u26FDh+SRRx5R96lSpYrq80Jt7OzZs/LVV185mxLh8ccfl19++UX69eunmhNbtWolb775ZtBeJ5FVsSZGIa1u3bry+uuvqzFjxYoVk9mzZ0uLFi1k6dKlKlDlN/EpAhX60bDoKo7Tvn17t79jZeChQ4eqLTExURYsWCBPP/10EbwqCnWaZldboMcwA9bEKOTdcsstsmHDBvnss89UhmHfvn0lKipKZSQisePo0aOqLwxNhCdPnnQ+DskfCHKvvPKKDBw40O2YOM7atWvVY3fv3q2Of+uttwbh1VFI0rT/NQcGsrFPjMg86tevL99++62zRoaswrFjx0rPnj3lwoULUqNGDenUqZNbzSwsLEz1jU2ZMkX69+/vdrycnByVoYigh8cgs/Fvf/tbEF4ZkbVxPTGiACBL8fz587Jy5cpgF4VIHOuJdSrfT4rbwgM61jUtW9Zn/J3riRFZEb7YSNjA+DIGMDIcu13EFmCflkn6xBjEiAoB/WUpKSkqaaNLly7BLg6RO9XAxnFiRJQHJHoQUfAxiBERWYxmt4tmC40UewYxIiKr0UKnOZHjxIiIyLRYEyMishq7hgFUIVETYxAjIrIaDQHIHhJBjM2JRERkWqyJERFZjGbXRAuwOdEskzmxJkZEZDWaXZ+tEAvM1q5dWyIjI6VNmzZqQoD8/OMf/5AGDRqo+2MB2dWrV/v9nAxiREQUMCxflJCQIElJSWrlhmbNmqmVHrDorDdbt25VSxlh/tEffvhB7r//frXt27fPr+flBMBERBabALij7QEpbisR0LGuaVdlo7bc5wmAUfPC6uhYkw/sdrtaUw9r6I0bNy7X/Xv16iWXLl2SVatWOfdhlfTY2FiZN2+ez+VkTYyIyGq0om1OzM7Oll27dknnzp3dlirC7W3btnl9DPa73h9Qc8vr/nlhYgcRkcVck6sBT9ihjvFH7c5VRESE2lylp6erNfSqVq3qth+3Dxw44PX4aWlpXu+P/f5gECMisojw8HCpVq2abEnzP0HCmzJlyqgmQVfo85o4caIYBYMYEZFFREZGytGjR1Xznh6QMmGz2dz2edbCICoqSq2IfvbsWbf9uI2g6g32+3P/vDCIERFZLJBFRkYWeQ2wZcuWsn79epVh6EjswO3hw4d7fUzbtm3V30eNGuXct27dOrXfHwxiREQUMKTXDxgwQFq1aiVxcXEyc+ZMlX04cOBA9ff+/ftLjRo1JDk5Wd0eOXKk3HnnnfL6669Lt27dZMmSJbJz506ZP3++X8/LIEZERAFDyvz58+dlwoQJKjkDqfJr1qxxJm+kpqaqjEWHdu3ayeLFi+XFF1+U559/XurVqycrVqyQxo0b+/W8HCdGRESmxXFiRERkWgxiRERkWgxiRERkWgxiRERkWgxiRERkWgxiRERkWgxiRERkWgxiRERkWgxiRERkWgxiRERkWgxiRERkWgxiREQkZvV/0HM9KFebrHoAAAAASUVORK5CYII="
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 33
  },
  {
   "cell_type": "code",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 960
    },
    "id": "cPeMjXO1N4yF",
    "outputId": "e6922ce8-ba71-491f-d7a6-709a14a4b7d7",
    "ExecuteTime": {
     "end_time": "2025-02-06T02:33:58.033532Z",
     "start_time": "2025-02-06T02:33:57.724614Z"
    }
   },
   "source": [
    "#通过下面代码查看mask的效果\n",
    "inputs_words = [\"The quick brown fox jumps over the lazy dog .\", \"What does the fox say ?\"]\n",
    "\n",
    "inputs_ids, input_mask = tokenizer.encode([w.split() for w in inputs_words], return_mask=True)\n",
    "for i in range(len(inputs_words)):\n",
    "    decode_text = tokenizer.decode(inputs_ids[i: i+1].tolist(), remove_bos=False, remove_eos=False, remove_pad=False, split=True)[0]\n",
    "    print(decode_text)\n",
    "    # print(input_mask[i].reshape(1, -1))\n",
    "    self_attn_mask  = input_mask[i].reshape(1, -1).repeat_interleave(inputs_ids.shape[-1], dim=0)\n",
    "    # print(input_mask[i].reshape(1, -1).repeat_interleave(inputs_ids.shape[-1], dim=0))\n",
    "    look_ahead_mask = generate_square_subsequent_mask(inputs_ids.shape[-1])\n",
    "\n",
    "    fig, axs = plt.subplots(1, 2, figsize=(10, 5))\n",
    "    axs[0].matshow(self_attn_mask)\n",
    "    axs[0].set_title(\"self_attn_mask\")\n",
    "    axs[0].set_yticks(range(len(decode_text)), decode_text, fontsize=6)\n",
    "    axs[0].set_ylabel(\"querys\")\n",
    "    axs[0].set_xticks(range(len(decode_text)), decode_text, fontsize=6)\n",
    "    axs[0].set_xlabel(\"keys\")\n",
    "    axs[1].matshow(look_ahead_mask)\n",
    "    axs[1].set_title(\"look_ahead_mask\")\n",
    "    axs[1].set_yticks(range(len(decode_text)), decode_text, fontsize=6)\n",
    "    axs[1].set_ylabel(\"querys\")\n",
    "    axs[1].set_xticks(range(len(decode_text)), decode_text, fontsize=6)\n",
    "    axs[1].set_xlabel(\"keys\")\n",
    "    plt.show()\n",
    "    print('-'*50)"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['[BOS]', '[UNK]', 'quick', 'brown', '[UNK]', 'jumps', 'over', 'the', '[UNK]', 'dog', '.', '[EOS]']\n",
      "tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])\n",
      "tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 1000x500 with 2 Axes>"
      ],
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1IAAAG1CAYAAADz+MUUAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAQQBJREFUeJzt3Qd8FNXa+PEnIRBpCYgIBKJ0pAoGBA0lXJrYQH0pggKCogheVEDJRUVRiYCgr1gQERRBynsFQa9Ik9ARUEJRUboJEQWBJKIEQub/eY7/3ZtGkknZ+vt+PpOdnZ2dMzObnWefM2fOBFiWZQkAAAAAIN8C8z8rAAAAAECRSAEAAACATSRSAAAAAGATiRQAAAAA2EQiBQAAAAA2kUgBAAAAgE0kUgAAAABgE4kUAAAAANhEIgUAAAAANpFIAZfxwQcfSEBAgBw9ejTT9ClTpkjt2rWlRIkS0rx5c7etn697/vnnzf4/deqUu1cFAPIdI4rKoEGDpFy5cuLq7dm5c6d4WhzwVsQx30ciBdiwatUqeeqppyQyMlLmzJkjEydOLNLlb9myxRx4z549m+01LevTTz8t0vIAAABQMCRSgA1fffWVBAYGyvvvvy8DBgyQW2+9tcgTqRdeeIFECgAAwMORSAE2/Pbbb1K6dGkpVaqUu1cFAAAAbkQiBZ+TkpIijz/+uNSsWVOCg4Pl6quvli5dusi3337rnOfrr7+WW265RUJDQ6VMmTLSoUMH2bx5c67L1XbO2pzv3LlzZlwHbVOeH3v27DHt3fXaqiuuuEKqVq0qgwcPlt9//905jzbpGzNmjBmvVauWswxtf6+PWu6HH37onK7Lc7xPnx88eNBMq1ChgtmuBx54QP78888Ctcn/+eef5fbbbzfj1atXl7feesu8vnfvXvnHP/4hZcuWlWuvvVY+/vjjTO8/ffq0jB49Wpo2bWreGxISIt27d5fdu3dnK2v69OnSuHFjs/8rVqwoLVu2zLa8rI4dOyZ169aVJk2ayK+//mpr2wCguL399tvmuKaxJywsTIYPH55jC4P/+7//k4iICFMxd9VVV8l9990nx48fz3P5cXFxUrlyZYmKipI//vgjX+ukx81HH31UGjRoYMqrVKmS9OrV67LXdqWmpsqTTz5pytFj/V133SUnT57MNt+KFSukXbt2Zp7y5cvLbbfdJt99953t2OewadMmadWqlZmvTp068u6770pBEMfgSkEuLQ1wgUceeUT+/e9/y4gRI6RRo0bmgK0H6B9++EFuuOEG0zxPD4oaxMaPH2+a6mmCpAfWjRs3yo033pjjcj/66COZOXOmbN++XWbNmmWm3Xzzzflap9WrV8vhw4dNcqOBRIONLksft23bZhKhu+++W3766SdZsGCBvPbaaya4Kg1mWvaDDz5o1m3o0KFmugaajHr37m0SsJiYGJM06jpqEjlp0iRb++/SpUtm/7Rv314mT54s8+fPN/tSg864ceOkf//+Zl1nzJhhmjfedNNNplyl26jNDzVI6zQNEhoMNVH9/vvvzQ8L9d5778k///lP+Z//+R8ZOXKknD9/3gRcTXD79euX43odOnTIfEZXXnml2Z+O/QMAnkArtbRpdufOnWXYsGHy448/yjvvvCM7duwwFXUlS5Y082kFnMYCTRr0eK3Hyf/93/818+zatctUhuVEl9OtWzfzY33ZsmUmKcoPfZ82G+/bt6/UqFHDJFC6XpqM6XFZk4CMHnvsMZMUaHzUeV9//XUTAxYtWuScR2PSwIEDzfpojNFKO11m27ZtzTZoRWZ+Y58juenatauJd7of09LSTPlVqlQp0GdBHIPLWICPCQ0NtYYPH57ja+np6Va9evWsbt26mXGHP//806pVq5bVpUsX57Q5c+ZY+hU5cuSIc9rAgQOtsmXL2l4nXX5WCxYsMMvfsGGDc9qUKVOylemg5Wr5WY0fP968Z/DgwZmm33XXXValSpVsracuX5c1ceJE57QzZ85YpUuXtgICAqyFCxc6p+/fv9/Mq+U7nD9/3rp06VKmZeq2BAcHWxMmTHBO69Gjh9W4ceNc18WxXSdPnrR++OEHKywszGrVqpV1+vRpW9sEAMUhY4z47bffrFKlSlldu3bNdAx88803zTyzZ882zy9cuGBdffXVVpMmTay//vrLOd/nn39u5nvuuedyjDebNm2yQkJCrNtuu80cZwsbf7Zu3WrKmzt3brbt6dy5c6b4+MQTT1glSpSwzp49a56npKRYFSpUsB566KFMyzxx4oSJvxmn5zf29ezZ07riiiusY8eOOad9//33ply7P1WJY3AlmvbB52htntYIJSYm5tgs4sCBA6a2SM9UaZekOmizuU6dOsmGDRskPT29yNcpY82h1lppmW3atDHPMzY5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"
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--------------------------------------------------\n",
      "['[BOS]', '[UNK]', 'does', 'the', '[UNK]', 'say', '?', '[EOS]', '[PAD]', '[PAD]', '[PAD]', '[PAD]']\n",
      "tensor([[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1]])\n",
      "tensor([[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1],\n",
      "        [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1]])\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 1000x500 with 2 Axes>"
      ],
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1AAAAG1CAYAAAD3DRUpAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAQFFJREFUeJzt3QucTfX6+PFnxjCuM3TDNFMhl5SQCX/CIINuk1tCIU4KlQrJq+MoyiQVujJ1kBK5TFdpiNxCumA4RW4xYyiOmplcxmXW//V8z2vv38wYZs2Y2XvtvT/v12uZtddee33X3mavZ57vetZ3BVmWZQkAAAAAoEDBBa8CAAAAAFAkUAAAAABgEwkUAAAAANhEAgUAAAAANpFAAQAAAIBNJFAAAAAAYBMJFAAAAADYRAIFAAAAADaRQAEAAACATSRQQD5mzZolQUFB8ttvv+VaPmnSJKlZs6aUKlVKGjVq5LX983fPPvus+fyPHDni7V0BANsxorj0799fKlasKJ5+Pz/88IM4LQ74KuKYfyOBAmxaunSpPPXUU9KyZUuZOXOmTJgwoVi3v27dOnPA/euvv855Ttv65JNPirU9AAAAFB4JFGDTihUrJDg4WP79739L37595bbbbiv2BOq5554jgQIAAHAwEijApj/++EPKlSsnZcqU8fauAAAAwEtIoOBXMjMz5fHHH5drrrlGQkND5YorrpAOHTrITz/95F7nu+++k06dOkl4eLiUL19e2rRpI99+++0Ft6t1zFq2d+zYMTOvk9aM25GcnGzq2fXaqbJly0q1atVkwIAB8t///te9jpbujRw50szXqFHD3YbW1+tPbfe9995zL9ftuV6nj3ft2mWWVa5c2byvBx54QI4fP16kmvv9+/fLHXfcYeavvPJKefPNN83zW7dulXbt2kmFChXk6quvlg8//DDX648ePSojRoyQBg0amNeGhYVJ586dZcuWLee09frrr8v1119vPv8qVapIdHT0OdvLa9++fXLttdfKDTfcIL///nuh3hsAlLS33nrLHNc09kRERMjQoUPzrShYsGCBNGnSxHTIXXbZZXLffffJgQMHCtz+5s2b5fLLL5eYmBj5+++/be2THjeHDBkidevWNe1deuml0qNHj/Neu5WVlSVPPvmkaUeP9V26dJHDhw+fs96SJUukVatWZp1KlSrJ7bffLv/5z38KHftc1q5dKzfffLNZr1atWjJ9+nQpCuIYPCXEYy0BHvDwww/LwoUL5ZFHHpH69eubA7UemH/55Re56aabTBmeHgw1eI0dO9aU5GlipAfUNWvWSNOmTfPd7vvvvy8JCQmyceNGeffdd82yFi1a2NqnZcuWyZ49e0xSowFEg4xuS39u2LDBJEBdu3aVX3/9VebOnSuTJ082QVVpENO2//GPf5h9GzRokFmuASane+65xyRe8fHxJlnUfdTkceLEiYX6/M6ePWs+n9atW8tLL70kc+bMMZ+lBptnnnlG+vTpY/Z12rRppozx//2//2faVfoetcxQg7Mu0+CgQVAT1J9//tn8QaHeeecdeeyxx6R79+4ybNgwOXnypAm0mtj27t073/3avXu3+T+65JJLzOfp+nwAwAm0M0tLsG+99VYZPHiw7NixQ95++235/vvvTQdd6dKlzXra8aaxQJMFPV7rcXLq1KlmnU2bNplOsPzodjp27Gj+SP/0009NMmSHvk7Lw++9916JjIw0iZPulyZhelzWP/5zevTRR00yoPFR150yZYqJAR999JF7HY1J/fr1M/ujMUY763Sbt9xyi3kP2oFpN/a5kprY2FgT7/RzPHPmjGm/atWqRfq/II7BIyzAj4SHh1tDhw7N97ns7Gyrdu3aVseOHc28y/Hjx60aNWpYHTp0cC+bOXOmpV+PvXv3upf169fPqlChQqH3Sbef19y5c832V69e7V42adKkc9p00Xa1/bzGjh1rXjNgwIBcy7t06WJdeumlhdpP3b5ua8KECe5lf/75p1WuXDkrKCjImjdvnnv59u3bzbravsvJkyets2fP5tqmvpfQ0FBr3Lhx7mVxcXHW9ddff8F9cb2vw4cPW7/88osVERFh3XzzzdbRo0cL9Z4AoCTkjBF//PGHVaZMGSs2NjbXMfCNN94w68yYMcM8PnXqlHXFFVdYN9xwg3XixAn3el988YVZ71//+le+8Wbt2rVWWFiYdfvtt5vj7MXGn/Xr15v2Zs+efc77ufXWW3PFxyeeeMIqVaqU9ddff5nHmZmZVuXKla0HH3ww1zYPHTpk4m/O5XZj3913322VLVvW2rdvn3vZzz//bNot7J+pxDF4CiV88Cvae6c9QGlpafmWP+zcudP0DumZKR1aVCctj2vfvr2sXr1asrOzi32fcvYUai+Vttm8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gE0kUAAAAABgEwkUAAAAANhEAgUAAAAANpFAAQAAAIBNJFAAAAAAYBMJFAAAAADYRAIFAAAAAL6QQK1cuVKioqIkISFBYmJipFWrVtK6dWvp3bu3nD171qyzdetWad++vbRp00buuOMOSUlJMcuTk5PNurq8RYsWcuDAAfn555+lUaNGMmLECG++LQCAjyIuAQAcfwaqZ8+eMmjQIDO/ZMkSWb16tVSsWFHWr18vp0+flvvuu88EslWrVsno0aPNYzV+/Hh5++23zfLly5fLpZdeKvXr15cpU6act62srCzJyMjINQEA4K24pIhNAOBbvJ5A5SczM1PCwsJkw4YNpueuVq1aZnnLli0lOzvb9PaVK1dOvv76azl27JiZL1u2bIHbjY+Pl/DwcPekvYwAAHgrLiliEwD4FkclUJ07d5bGjRtLamqqXHfddZKWliYRERG51omMjDTLJ02aJL/88os0bNjQ9BZqwCqI9hSmp6e7J1fZBQAA3ohLitgEAL7FUQmUlkps2rRJevToIa+88opUr17dBKWcNIhp8KpatapMmzZNdu3aJbVr15b333+/wO2HhoaaHsScEwAA3opLitgEAL7FUQmUS5UqVeSPP/6Q5s2by08//SS7d+82y7/99lvzU8sbdu7c6V7/8ssvF8uyvLa/AAD/RlwCALiEiMNKJUqVKmXqyd977z0pU6aMfPDBB/Lggw+a0Y8qVKhgHqt58+bJF198YerMK1eu7F4OAEBxIS4BAByVQOkFtsuWLTOjGenQsfnRWvIVK1acs3zMmDFmykmHi3366aflrrvuKrF9BgD4L+ISAKAgQVYA1xjoULE64lGMxElIUGlv7w6AC0hK2+ztXUAxysjMlip19phBE7jmxxmxie8YgECXYTM2OfIaKAAAAABwIhIoAAAAALCJBAoAAAAAbCKBAgAAAACbSKAAAAAAwCYSKAAAAACwiQQKAAAAAHzhRroAAMAZOkY08kq73H8KgK/hDBQAAAAA2EQCBQAAAAA2kUABAAAAgE0kUAAAAABgEwkUAAAAANhEAgUAAAAANpFAAQAAAIBNJFAAAAAAYBMJFAAAAADYRAIFAAAAADaRQAEAAACATSRQAAAAAOD0BGrlypUSFRUlCQkJEh0dnes51+P+/ftL586dz1murx0xYoSZX79+vbRs2VL++usv6du3r0RGRnr0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"
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--------------------------------------------------\n"
     ]
    }
   ],
   "execution_count": 40
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "outputs": [
    {
     "data": {
      "text/plain": "tensor([[False,  True,  True,  True,  True],\n        [False, False,  True,  True,  True],\n        [False, False, False,  True,  True],\n        [False, False, False, False,  True],\n        [False, False, False, False, False]])"
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(torch.triu(torch.ones(5, 5)) == 0).transpose(-1, -2).bool()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-08-05T08:06:27.179078300Z",
     "start_time": "2024-08-05T08:06:26.513547400Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "outputs": [
    {
     "data": {
      "text/plain": "torch.Size([5, 1, 4, 4])"
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#帮我随机两个[5, 1, 1, 4]与[1, 1, 4, 4]尺寸的张量，并求和\n",
    "a = torch.randn(5, 1, 1, 4)\n",
    "b = torch.randn(1, 1, 4, 4)\n",
    "(a + b).shape"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-08-05T08:06:27.234057200Z",
     "start_time": "2024-08-05T08:06:27.159090100Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "TelCDOoEN4yF"
   },
   "source": [
    "#### Transformer Model"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "oFGNt8FPN4yF",
    "ExecuteTime": {
     "end_time": "2025-02-06T03:11:56.433217Z",
     "start_time": "2025-02-06T03:11:56.423245Z"
    }
   },
   "source": [
    "@dataclass\n",
    "class TransformerOutput:\n",
    "    logits: Tensor\n",
    "    encoder_last_hidden_states: Tensor\n",
    "    encoder_attn_scores: List[Tensor] #画图\n",
    "    decoder_last_hidden_states: Tensor\n",
    "    decoder_self_attn_scores: List[Tensor] #画图\n",
    "    decoder_cross_attn_scores: List[Tensor] #画图\n",
    "    preds: Optional[Tensor] = None\n",
    "\n",
    "class TransformerModel(nn.Module):\n",
    "    def __init__(self, config):\n",
    "        super().__init__()\n",
    "        # hyper params\n",
    "        self.hidden_size = config[\"d_model\"]\n",
    "        self.num_encoder_layers = config[\"num_encoder_layers\"]\n",
    "        self.num_decoder_layers = config[\"num_decoder_layers\"]\n",
    "        self.pad_idx = config[\"pad_idx\"]\n",
    "        self.bos_idx = config[\"bos_idx\"]\n",
    "        self.eos_idx = config[\"eos_idx\"]\n",
    "        self.vocab_size = config[\"vocab_size\"]\n",
    "        self.dropout_rate = config[\"dropout\"]\n",
    "        self.max_length = config[\"max_length\"]\n",
    "        self.share = config[\"share_embedding\"] # 是否共享词嵌入，共享后，decoder的词嵌入层和encoder的词嵌入层相同，节省内存\n",
    "\n",
    "        # layers\n",
    "        self.src_embedding = TransformerEmbedding(config) # 输入的嵌入层\n",
    "        if self.share:#如果共享词嵌入，则使用src_embedding作为trg_embedding\n",
    "            self.trg_embedding = self.src_embedding #源和目标的嵌入层相同，共享参数，节省内存\n",
    "            self.linear = lambda x: torch.matmul(\n",
    "                x, self.trg_embedding.get_word_embedding_weights().T\n",
    "            ) # 输出层，共享参数，直接拿原有embedding矩阵的转置，节省内存\n",
    "        else:\n",
    "            self.trg_embedding = TransformerEmbedding(config) #decoder模块的嵌入层\n",
    "            self.linear = nn.Linear(self.hidden_size, self.vocab_size) # 输出层\n",
    "\n",
    "        self.encoder = TransformerEncoder(config)\n",
    "        self.decoder = TransformerDecoder(config)\n",
    "\n",
    "        # init weights\n",
    "        self._init_weights()\n",
    "\n",
    "    def _init_weights(self):\n",
    "        \"\"\"使用 xavier 均匀分布来初始化权重\"\"\"\n",
    "        for p in self.parameters():\n",
    "            if p.dim() > 1:\n",
    "                nn.init.xavier_uniform_(p)\n",
    "\n",
    "    def generate_square_subsequent_mask(self, sz: int) -> Tensor:\n",
    "        \"\"\"\n",
    "        Generate a square mask for the sequence. The masked positions are filled with True.\n",
    "            Unmasked positions are filled with False.为了生成斜三角的mask\n",
    "        \"\"\"\n",
    "        mask = (torch.triu(torch.ones(sz, sz)) == 0).transpose(-1, -2).bool()\n",
    "\n",
    "        return mask\n",
    "\n",
    "    def forward(\n",
    "        self, encoder_inputs, decoder_inputs, encoder_inputs_mask=None\n",
    "    ) -> TransformerOutput:\n",
    "        # encoder_inputs: [batch_size, src_len]\n",
    "        # decoder_inputs: [batch_size, trg_len]\n",
    "        # encoder_inputs_mask: [batch_size, src_len]\n",
    "        if encoder_inputs_mask is None:\n",
    "            encoder_inputs_mask = encoder_inputs.eq(self.pad_idx) # [batch_size, src_len]\n",
    "        encoder_inputs_mask = encoder_inputs_mask.unsqueeze(1).unsqueeze(\n",
    "            2\n",
    "        )  # [batch_size, 1, 1, src_len],用于encoder的自注意力\n",
    "        look_ahead_mask = self.generate_square_subsequent_mask(decoder_inputs.shape[1])\n",
    "        look_ahead_mask = (\n",
    "            look_ahead_mask.unsqueeze(0).unsqueeze(0).to(decoder_inputs.device)\n",
    "        )  #[trg_len, trg_len]--> [1, 1, trg_len, trg_len],用于decoder的自注意力\n",
    "        #增加decoder_inputs_mask和look_ahead_mask进行组合\n",
    "        decoder_inputs_mask = decoder_inputs.eq(self.pad_idx) # [batch_size, trg_len]，和上面encoder_inputs_mask一致\n",
    "        # print(decoder_inputs_mask.shape)\n",
    "        decoder_inputs_mask = decoder_inputs_mask.unsqueeze(1).unsqueeze(2)  # [batch_size, 1, 1, trg_len]\n",
    "        # print(decoder_inputs_mask.shape)\n",
    "        decoder_inputs_mask = decoder_inputs_mask + look_ahead_mask # [batch_size, 1, 1, trg_len]与[1, 1, trg_len, trg_len]相加，得到decoder的自注意力mask\n",
    "\n",
    "        # encoding\n",
    "        encoder_inputs_embeds = self.src_embedding(encoder_inputs)\n",
    "        encoder_outputs = self.encoder(encoder_inputs_embeds, encoder_inputs_mask) #encoder_inputs_mask用于encoder的自注意力,广播去做计算\n",
    "\n",
    "        # decoding\n",
    "        decoder_inputs_embeds = self.trg_embedding(decoder_inputs)\n",
    "        decoder_outputs = self.decoder(\n",
    "            decoder_inputs_embeds=decoder_inputs_embeds,\n",
    "            encoder_outputs=encoder_outputs.last_hidden_states,\n",
    "            attn_mask=decoder_inputs_mask, #用于decoder的自注意力,广播去做计算\n",
    "            cross_attn_mask=encoder_inputs_mask,#用于decoder的交叉注意力,广播去做计算\n",
    "        )\n",
    "\n",
    "        logits = self.linear(decoder_outputs.last_hidden_states) # [batch_size, trg_len, vocab_size]\n",
    "\n",
    "        return TransformerOutput(\n",
    "            logits=logits,\n",
    "            encoder_last_hidden_states=encoder_outputs.last_hidden_states,\n",
    "            encoder_attn_scores=encoder_outputs.attn_scores,\n",
    "            decoder_last_hidden_states=decoder_outputs.last_hidden_states,\n",
    "            decoder_self_attn_scores=decoder_outputs.self_attn_scores,\n",
    "            decoder_cross_attn_scores=decoder_outputs.cross_attn_scores,\n",
    "        )\n",
    "\n",
    "    @torch.no_grad()\n",
    "    def infer(self, encoder_inputs, encoder_inputs_mask=None) -> Tensor:\n",
    "        # assert len(encoder_inputs.shape) == 2 and encoder_inputs.shape[0] == 1\n",
    "        if encoder_inputs_mask is None:#应对多个样本同时进行推理\n",
    "            encoder_inputs_mask = encoder_inputs.eq(self.pad_idx)\n",
    "        encoder_inputs_mask = encoder_inputs_mask.unsqueeze(1).unsqueeze(2)  # [batch_size, 1, 1, src_len],[1,src_len]相加时，会自动广播到[batch_size,1,src_len,src_len]\n",
    "        look_ahead_mask = self.generate_square_subsequent_mask(self.max_length)\n",
    "        look_ahead_mask = (\n",
    "            look_ahead_mask.unsqueeze(0).unsqueeze(0).to(encoder_inputs.device)\n",
    "        )  # [1, 1, trg_len, trg_len]\n",
    "\n",
    "        # encoding\n",
    "        encoder_inputs_embeds = self.src_embedding(encoder_inputs)\n",
    "        encoder_outputs = self.encoder(encoder_inputs_embeds) #因为只支持单样本预测，没有paddings，所以不需要mask\n",
    "\n",
    "        # decoding,多样本推理\n",
    "        decoder_inputs = torch.Tensor([self.bos_idx] * encoder_inputs.shape[0]).reshape(-1, 1).long().to(device=encoder_inputs.device)\n",
    "        for cur_len in tqdm(range(1, self.max_length + 1)):\n",
    "            decoder_inputs_embeds = self.trg_embedding(decoder_inputs)\n",
    "            decoder_outputs = self.decoder(\n",
    "                decoder_inputs_embeds=decoder_inputs_embeds,\n",
    "                encoder_outputs=encoder_outputs.last_hidden_states,\n",
    "                attn_mask=look_ahead_mask[:, :, :cur_len, :cur_len],#decoder的自注意力mask\n",
    "            )\n",
    "\n",
    "            logits = self.linear(decoder_outputs.last_hidden_states)\n",
    "            next_token = logits.argmax(dim=-1)[:, -1:] #通过最大下标确定类别，[:, -1:]表示取最后一个结果\n",
    "            decoder_inputs = torch.cat([decoder_inputs, next_token], dim=-1) #预测输出拼接到输入中\n",
    "            #(decoder_inputs == self.eos_idx).sum(dim=-1)是判断样本中是否含有EOS标记\n",
    "            #all是每一个都为True，才会结束\n",
    "            if all((decoder_inputs == self.eos_idx).sum(dim=-1) > 0):\n",
    "                break\n",
    "\n",
    "        return TransformerOutput(\n",
    "            preds=decoder_inputs[:, 1:],\n",
    "            logits=logits,\n",
    "            encoder_last_hidden_states=encoder_outputs.last_hidden_states,\n",
    "            encoder_attn_scores=encoder_outputs.attn_scores,\n",
    "            decoder_last_hidden_states=decoder_outputs.last_hidden_states,\n",
    "            decoder_self_attn_scores=decoder_outputs.self_attn_scores,\n",
    "            decoder_cross_attn_scores=decoder_outputs.cross_attn_scores,\n",
    "        )"
   ],
   "outputs": [],
   "execution_count": 41
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "kXHQ3sGTN4yG"
   },
   "source": [
    "## 训练"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "OxNA8DIzN4yG"
   },
   "source": [
    "### 损失函数"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "1xzahHANN4yG",
    "ExecuteTime": {
     "end_time": "2025-02-06T03:16:20.185187Z",
     "start_time": "2025-02-06T03:16:20.181945Z"
    }
   },
   "source": [
    "class CrossEntropyWithPadding:\n",
    "    def __init__(self, config):\n",
    "        self.label_smoothing = config[\"label_smoothing\"]\n",
    "\n",
    "    def __call__(self, logits, labels, padding_mask=None):\n",
    "        # logits.shape = [batch size, sequence length, num of classes]\n",
    "        # labels.shape = [batch size, sequence length]\n",
    "        # padding_mask.shape = [batch size, sequence length]\n",
    "        bs, seq_len, nc = logits.shape\n",
    "        loss = F.cross_entropy(logits.reshape(bs * seq_len, nc), labels.reshape(-1), reduce=False, label_smoothing=self.label_smoothing) #label_smoothing表示随机将一个类别的概率设置为0.1，使得模型更加关注其他类别\n",
    "        if padding_mask is None:\n",
    "            loss = loss.mean()\n",
    "        else:\n",
    "            padding_mask = 1 - padding_mask.reshape(-1) #将padding_mask reshape成一维张量，mask部分为0，非mask部分为1\n",
    "            loss = torch.mul(loss, padding_mask).sum() / padding_mask.sum()\n",
    "\n",
    "        return loss\n"
   ],
   "outputs": [],
   "execution_count": 42
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "zuBC9KqFN4yG"
   },
   "source": [
    "### 学习率衰减"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "outputs": [
    {
     "data": {
      "text/plain": "[<matplotlib.lines.Line2D at 0x210b5030380>]"
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": "<Figure size 640x480 with 1 Axes>",
      "image/png": "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RUREpBH6dHcuz763nQslFfh6e/C7hwZwd1gHR8dqMCosIiIijUh5pY3fr9/LX748AsCAzv4kJ0TRpW1zBydrWCosIiIijcTxcyVMWpbB9uMXAPj5zd2YcVcoXh5ujg12A6iwiIiINALrs3J47r3tFJZW4ufjwbyHw7mjX5CjY90wKiwiIiJOrKzSStK6vby95SgAkV1asSghks6tXXsJ6PtUWERERJzUsbPFTFqawc6TBQD84rbuPBvXG093118C+j4VFhERESe0dscpZry/k4tllbRu7sn8R8L5cWigo2M5jAqLiIiIEymtsPLbtbt555tsAAaHtGZhQiQd/Js5OJljqbCIiIg4icNnLjJxaQZ7ThcC8MvbbyLxJ73waIJLQN+nwiIiIuIEVmecZNaqnZSUW2nbwovX4iMY3qudo2M5DRUWERERB7pUbuXXa3axYttxAIZ2b8ProyMJ9PNxcDLnosIiIiLiIAfzipj4Tgb7couwWGDKj3syZURP3N0sjo7mdFRYREREHOC9tBO8uDqLSxVW2vl683p8BMN6BDg6ltNSYREREbmBissqefHDLD5IPwnALT0C+EN8BO18vR2czLmpsIiIiNwge3MKmfhOOofOFONmgcSf9OKp23toCagWVFhEREQamDGGFd8eZ86aXZRV2gj082bh6Eiiu7d1dLRGo04v7F68eDEhISH4+PgQHR3N1q1brzp2165dPPjgg4SEhGCxWFiwYME1H3vu3LlYLBamTZtWl2giIiJO5WJZJVOXZzLjg52UVdoY3qsd66bcqrJiJ7sLy4oVK0hMTGTOnDmkp6cTHh5OXFwceXl5NY4vKSmhe/fuzJ07l6Cga3+q5Lfffsuf/vQnBgwYYG8sERERp7PrVAH3LPqSNdtP4e5m4fk7Q3nrZ4Np21LXq9jL7sLy2muv8fjjjzNhwgT69u3LkiVLaN68OX/9619rHD948GBeffVVRo8ejbf31Q/QxYsXGTt2LH/+859p3bq1vbFERESchjGG//36GPf/cQtH8ovp6O/Du78YylO334SbrlepE7sKS3l5OWlpacTGxv7rAdzciI2NJTU19QcFmThxIiNHjqz22NdSVlZGYWFhtZuIiIijFZZWMGlpBi+uzqK80kZsn/Z8NOVWBnZt4+hojZpdF93m5+djtVoJDKz+aZGBgYHs3bu3ziGWL19O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QIDJy8szxlx+6VqXLl3MZ599ZrZt22ZiYmJMTExM1f7fvXTtjjvuMJmZmWb9+vWmXbt2Nb50bfr06WbPnj1m8eLFDfay5qKiIpORkWEyMjIMYF577TWTkZFhjh07Zoy5/LLmVq1amQ8//NDs2LHD3HfffTW+rDkyMtJ888035ssvvzQ9e/as9pLfCxcumMDAQPPoo4+arKwss3z5ctO8efMrXvLr4eFh5s2bZ/bs2WPmzJlTby9rvtYci4qKzLPPPmtSU1PNkSNHzKeffmqioqJMz549TWlpaaOY41NPPWX8/f3Nxo0bq70stKSkpGrMjfq5bIjf4+vN7+DBg+Y3v/mN2bZtmzly5Ij58MMPTffu3c1tt93WKOZnjDEzZswwmzZtMkeOHDE7duwwM2bMMBaLxfzzn/80xjTu43e9+bnC8avJ91/51NiOoQrLdSxatMh06dLFeHl5mSFDhpivv/7a0ZGuEB8fbzp06GC8vLxMp06dTHx8vDl48GDV/ZcuXTK//OUvTevWrU3z5s3N/fffb06fPl3tMY4ePWruuusu06xZMxMQEGCeeeYZU1FRUW3M559/biIiIoyXl5fp3r27eeuttxpkPp9//rkBrriNHz/eGHP5pc0vvviiCQwMNN7e3mbEiBFm37591R7j7NmzJiEhwbRs2dL4+fmZCRMmmKKiompjtm/fbm655Rbj7e1tOnXqZObOnXtFlnfffdf06tXLeHl5mX79+pmPPvqowedYUlJi7rjjDtOuXTvj6elpunbtah5//PErfrmdeY41zQ2o9jNzI38u6/v3+Hrzy87ONrfddptp06aN8fb2Nj169DDTp0+v9j4ezjw/Y4z5+c9/brp27Wq8vLxMu3btzIgRI6rKijGN+/hdb36ucPxq8v3C0tiOocUYY+x7TkZERETkxtI1LCIiIuL0VFhERETE6amwiIiIiNNTYRERERGnp8IiIiIiTk+FRURERJyeCouIiIg4PRUWERERcXoqLCIiIuL0VFhERETE6amwiIiIiNNTYRERERGn939a+EZEJEJHuwAAAABJRU5ErkJggg=="
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "x=np.arange(1, 40000)\n",
    "plt.plot(x, x * (4000 ** (-1.5)))"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-08-05T08:06:27.235056800Z",
     "start_time": "2024-08-05T08:06:27.160089800Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "outputs": [
    {
     "data": {
      "text/plain": "22.627416997969522"
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.sqrt(512)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-08-05T08:06:27.235056800Z",
     "start_time": "2024-08-05T08:06:27.161089200Z"
    }
   }
  },
  {
   "cell_type": "code",
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 449
    },
    "id": "UQPiKK4nN4yG",
    "outputId": "63cfb132-ef75-4f94-f0c8-86a2f36e09c2",
    "ExecuteTime": {
     "end_time": "2025-02-06T03:18:28.334579Z",
     "start_time": "2025-02-06T03:18:28.281593Z"
    }
   },
   "source": [
    "# NoamDecayScheduler 是一个自定义或外部定义的学习率衰减调度器类。它需要接收配置 config 作为参数，可能实现了特定的学习率衰减方案\n",
    "class NoamDecayScheduler:\n",
    "    def __init__(self, config):\n",
    "        self.d_model = config[\"d_model\"]\n",
    "        self.warmup_steps = config[\"warmup_steps\"]\n",
    "\n",
    "    def __call__(self, step):\n",
    "        step += 1\n",
    "        arg1 = step ** (-0.5) #4000步之后是arg1\n",
    "        arg2 = step * (self.warmup_steps ** (-1.5))  #4000步之前是arg2\n",
    "\n",
    "        arg3 = self.d_model ** (-0.5)\n",
    "\n",
    "        return arg3 * np.minimum(arg1, arg2)\n",
    "\n",
    "\n",
    "temp_learning_rate_schedule = NoamDecayScheduler({\"d_model\": 512, \"warmup_steps\": 4000})\n",
    "#下面是学习率的设计图\n",
    "plt.plot(temp_learning_rate_schedule(np.arange(0, 40000)))\n",
    "plt.ylabel(\"Leraning rate\")\n",
    "plt.xlabel(\"Train step\")\n",
    "plt.grid()\n",
    "plt.show()\n"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ],
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlEAAAGwCAYAAACJjDBkAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAZ9xJREFUeJzt3Ql4VNXZB/B/9g2yEbNBSNj3RUAQRLBlFWoBEQGpKFKwVlooCoplkeUrikJZlSKi0kJBFFERKJFFUDDsO4EAIQlbQhJCSEL2+Z73hBknIYlJmMnM3Pn/nuc4M3fO3LnHmZA3Z3mPg06n04GIiIiIKsWxctWJiIiISDCIIiIiIqoCBlFEREREVcAgioiIiKgKGEQRERERVQGDKCIiIqIqYBBFREREVAXOVXkRVUxhYSGuXbuGmjVrwsHBwdKXQ0RERBUgKTTv3LmD0NBQODqW3d/EIMqMJIAKCwuz9GUQERFRFSQkJKBOnTplPs8gyoykB0r/IXh7e5vsvHl5edi+fTt69+4NFxcXaI3W22cPbdR6++yhjWyf7dN6G/PM2L709HTVCaL/PV4WBlFmpB/CkwDK1EGUp6enOqdWfzC03D57aKPW22cPbWT7bJ/W25hXDe37tak4nFhOREREVAUMooiIiIiqgEEUERERURUwiCIiIiKqAgZRRERERFXAIIqIiIioChhEEREREVUBgygiIiKiKmAQRURERFQFDKKIiIiIbDWIWrZsGSIiIuDu7o5OnTrhwIED5dbfsGEDmjZtquq3atUKW7ZsuW/35enTpyMkJAQeHh7o2bMnYmJiitVJTU3FiBEjVLp4X19fjB49GhkZGYbn3377bZXuvWTx8vIyceuJiIjIFlk8iFq/fj0mTpyIGTNm4MiRI2jTpg369OmDpKSkUuvv27cPw4cPV0HP0aNHMXDgQFVOnTplqDNv3jwsXrwYy5cvR1RUlAp85JzZ2dmGOhJAnT59GpGRkdi8eTP27NmDsWPHGp5//fXXcf369WKlefPmGDJkiJn/jxAREZEtsPgGxAsWLMCYMWMwatQo9VgCn++++w6rVq3Cm2++eV/9RYsWoW/fvpg0aZJ6PHv2bBUILV26VL1WeqEWLlyIqVOnYsCAAarO6tWrERQUhE2bNmHYsGE4e/Ystm3bhoMHD6JDhw6qzpIlS9CvXz+8//77CA0NRY0aNVTRO378OM6cOaPeoyw5OTmqGO8Crd8kUYqp6M9lynOam3wuBYU6ODs5arJ9laX1Nmq9ffbQRrbP9mm9jXlmbF9Fz+mgk99uFpKbm6t2YP7iiy9Ub5LeCy+8gLS0NHz99df3vaZu3bqq52rChAmGY9KLJQGSBDqXLl1CgwYNVC9V27ZtDXW6d++uHksQJgHaa6+9hlu3bhmez8/PV8ODMlQ4aNCg+973L3/5C7Zv345z586V2R4ZApw5c+Z9x9euXavaac8+PueI2DsOmNy6AN6ulr4aIiKismVlZeG5557D7du31bQfq+yJSk5ORkFBgeolMiaPo6OjS33NjRs3Sq0vx/XP64+VVycwMLDY887OzvD39zfUMSbDgGvWrCm1Z8zYlClTVIBn3BMVFhaG3r17l/shVCVClt63Xr16wcXFBdausFCH8fsj1f3rNRpjWM+GmmpfVWi9jVpvnz20ke2zfVpvY54Z26cfSbL64Txb8NVXX+HOnTuqh6w8bm5uqpQkH645vsDmOq+pXUu7a7h/PimzwtdsK+17EFpvo9bbZw9tZPtsn9bb6GKG9lX0fBadWB4QEAAnJyckJiYWOy6Pg4ODS32NHC+vvv721+qUnLguw3myYq+09125ciV+97vf3de7RRUTn5pluB91KQV5BYUWvR4iIiJTsGgQ5erqivbt22PHjh2GY4WFhepx586dS32NHDeuL6Q7T1+/Xr16KhAyriPdcrJKT19HbmXO1eHDhw11du7cqd5bUiwYi42Nxa5du9RqQHrwIOpOTj6OJaRZ9HqIiIhMweLDeTKHSIbJZJVcx44d1cq6zMxMw2q9kSNHonbt2pg7d656PH78eDVJfP78+ejfvz/WrVuHQ4cOYcWKFep5yeUkk87nzJmDRo0aqaBq2rRpasWdfvJ6s2bN1Ao/WRUoq+1kXHXcuHFq5Z7UMyaT0CXf1JNPPlnt/2+0Ij7llyBK/HDuJh6J8LfY9RAREWkiiBo6dChu3rypkmPKpG5ZQSfpB/RDZ/Hx8XB0/KXDrEuXLmq1m6QweOutt1SgJCvzWrZsaagzefJkFYhJ3ifpceratas6p6y+05OJ4hI49ejRQ51/8ODBKreUMemZ+vTTT/Hiiy+qYUd6sJ6opsE1EX3jDn44fxOv92li6csiIiKy7SBKSDAjpTS7d+++75gkvCwv6aX0Rs2aNUuVsshKPAnGyiPBVUJCQrl1qOJB1IhHwzFt0ymcvHobyRk5CKhx/yR8IiIiW2HxjOVkP0FUu7q+aBFalOphb8xNC18VERHRg2EQRWZ1JzsPqZm56n6Yvye6N37IMC+KiIjIljGIIrNKSC3KEeXn6QJvdxdDELUnJlltA0NERGSrGESRWcWnZqrburW81G27cD94uzur3qljCb9su0NERGRrGERRtcyHqutftHegi5MjftO0aMud7WeKJ0QlIiKyJQyiqFqCqPB7QZTo2awofcX3DKKIiMiGMYgis4pLKd4TJbo3eQguTg64eDMTl25mWPDqiIiIqo5BFJlVwr2eKFmZpycTzB+tX0vd//4se6OIiMg2MYgis5HVd1duFa3OC6/1SxBVfEiv+EbQREREtoJBFJnNtbS7yC/UwdXJEUHev2y5I3o2LwqiDsWlGvJIERER2RIGUWT2obw6fh5wcnQo9lxtXw80D/GGpIraGc3eKCIisj0Mosj86Q1KDOWV7I3afvpGtV4XERGRKTCIIrOJK5EjqqTe94KoH87fRGZOfrVeGxER0YNiEEXVlmizJNmMOKKWJ3LyC7GDQ3pERGRjGESR2cSXkiPKmIODA/q1ClH3t5y4Xq3XRkRE9KAYRJHF5kQJfRC161wSh/SIiMimMIgis7idlYfbd/PU/TC/soMoGdILvzekx1V6RERkSxhEkVl7oQJquMHLzbnMesZDet9xSI+IiGwIgygy86Ryj1+t259DekREZIMYRJFFVuYZ45AeERHZIgZRZBbxqZnqtm4tr1+tazyk9+3xa2a/NiIiIlNgEEUW74kSA9qGGob00rKKJqQTERFZMwZRZBVBVNNgbzQL8UZegQ5bTnEbGCIisn4Mosjk8goKcS0tW92XuU4VNejhot6ob45zlR4REVk/BlFkctfS7qKgUAc3Z0c8VMOtwq8b0LY2HB2Aw/FpSC6KwYiIiKwWgygy21BemL8nHCUqqqAgb3c81jBA3T+cXPHXERERWQKDKDK5uHt75oVXcD6UsYFta6vbgzcdodPpTH5tREREpsIgikwuwagnqrL6tgyGh4sjbmY74MTVdDNcHRERkWkwiCKLr8wzJlvE9GwWqO5/dZQ5o4iIyHoxiCLzDedVYmWesacfLhrS++bEdWTnFZj02oiIiEyFQRSZlMxjSniAnijRpb4//N10uJOdj62nmO6AiIisE4MoMinJNn7n3ibCVZkTJWRF36OBher+ugMJJr0+IiIiU2EQRSYVd68XKsjbDe4uTlU+T6eHdCpnVFRsKi7dzDDhFRIREZkGgyiymknlxnzdgG6NinJGrT/E3igiIrI+DKLIpH6ZD+X1wOd6tn0ddfvl4StqKxkiIiJrwiCKTCouJdMkPVHiiSYBCKjhhuSMXOw4m2SCqyMiIjIdBlFknuG8Wh4PfC4XJ0c8c683ak1U3AOfj4iISFNB1LJlyxAREQF3d3d06tQJBw4cKLf+hg0b0LRpU1W/VatW2LJly31L7KdPn46QkBB4eHigZ8+eiImJKVYnNTUVI0aMgLe3N3x9fTF69GhkZGTcd573338fjRs3hpubG2rXro3/+7//M2HLtSkh9a7JhvPEcx3rwsEB2BuTzAnmRERkVSwaRK1fvx4TJ07EjBkzcOTIEbRp0wZ9+vRBUlLpQzf79u3D8OHDVdBz9OhRDBw4UJVTp04Z6sybNw+LFy/G8uXLERUVBS8vL3XO7OxsQx0JoE6fPo3IyEhs3rwZe/bswdixY4u91/jx47Fy5UoVSEVHR+Obb75Bx44dzfh/w/bl5Bfg2u27JhvOU+ep5YnfNinKYL56P3ujiIjIejhb8s0XLFiAMWPGYNSoUeqxBD7fffcdVq1ahTfffPO++osWLULfvn0xadIk9Xj27NkqEFq6dKl6rfQeLVy4EFOnTsWAAQNUndWrVyMoKAibNm3CsGHDcPbsWWzbtg0HDx5Ehw4dVJ0lS5agX79+KmAKDQ1VdT788EMVnDVp0kTVqVev3q+2JycnRxW99PSivd/y8vJUMRX9uUx5TlOIS86E7Bns6eoEHzeHKl9fyfaN6FQHO6KT8MXhKxj/2/qo4WbRr62mP0NT0Xr77KGNbJ/t03ob88zYvoqe02K/jXJzc3H48GFMmTLFcMzR0VENv+3fv7/U18hx6bkyJr1MEiCJ2NhY3LhxQ51Dz8fHRw0TymsliJJbGcLTB1BC6st7S8/VoEGD8O2336J+/fqql0qCNgnOpI70cvn7+5fZprlz52LmzJn3Hd++fTs8PU3TM2NMAkhrcuaWAwAn+DjnY+vWrSZrX6EOCHR3QlJ2Pv6xJhJdg3XQCmv7DE1N6+2zhzayfbZP622MNEP7srKK5vdabRCVnJyMgoIC1UtkTB7L8FlpJEAqrb4c1z+vP1ZencDAouEhPWdnZxUc6etcunQJcXFxav6V9GTJdf7tb3/DM888g507d5bZJgkIjYM86YkKCwtD79691fwrU0bI8qXp1asXXFxcYC1So+KB6Gi0qBuIfv0eNmn7UmvFY/Z30Tia4Y3/e7ILHGSilA2z1s/QVLTePntoI9tn+7Texjwztk8/kvRrbH9cxAwKCwvVsJwEUDKxXHz88cdo3749zp07ZxjiK0kmoEspST5cc3yBzXXeqrqaVjSUGR5QwyTXZdy+Zx+piwWRMbhwMxOH4tPRpWFRIk5bZ22foalpvX320Ea2z/ZpvY0uZmhfRc9nsYnlAQEBcHJyQmJiYrHj8jg4OLjU18jx8urrb3+tTsmJ6/n5+WrFnr6OrOyT3il9ACWaNWumbuPj46vcZnvZ8iW8lumHLmu6u+DpdkXpDj7Zd9nk5yciIqosiwVRrq6uqmdnx44dxXqA5HHnzp1LfY0cN64vpCtPX18mf0sgZFxHuuRkrpO+jtympaWp+Vh6MkQn7y1zp8Rjjz2mAquLFy8a6pw/f17dhoeHm+j/gHazlVd14+Ff80KXCHX7/dlEpjsgIiL7TnEg84c++ugjfPbZZ2pF3CuvvILMzEzDar2RI0cWm3guaQdkZd38+fPVvKm3334bhw4dwrhx49TzMk9mwoQJmDNnjkpJcPLkSXUOWXEnqRD0PUoyWVxWBUpOqp9++km9XiadSz0hk8jbtWuHl156SaVSkIDr5ZdfVuOuxr1T9AuZfG+qffPK0jCwBno0DVQrAFf+GGuW9yAiIrKJIGro0KEqrYAkx2zbti2OHTumgiT9xHAZOrt+/bqhfpcuXbB27VqsWLFC5ZT64osv1Mq8li1bGupMnjwZf/nLX1Tep0ceeUQl0ZRzSnJOvTVr1qiEnT169FCpDbp27arOqScr9WSFngw5duvWDf3791fB17p166rt/42tka1ZsnILVGLMOn4Pnq28LGO71Ve3ku4gOeOXdBJERETVzeITy6UXSN+TVNLu3bvvOzZkyBBVyiK9UbNmzVKlLLIST4Kx8kiv1JdfflluHfqFvhcqxNsdbs5OZnufjvX80SbMF8cT0rB632VM7F36JH8iIiLNb/tC2mDu+VDGQfLL93qjVv8ch6zcfLO+HxERUVkYRJFJxKWYb2VeSX1aBKv3ScvKw4ZDV8z+fkRERKVhEEUmYe5J5cacHB3wx65F2/Cs/PES8gsKzf6eREREJTGIIpsaztN7pn0Y/L1ckZB6F18fu1Yt70lERGSMQRSZRFxqproNr+VVLe/n4eqEMY8XzY1auusCCmSDPSIiomrEIIoeWHZeARLTc6ptOE/v+c7h8PV0QWxyJjafYG8UERFVLwZR9MCu3Coayqvp5gw/z+rbn6mGm7NhbtSSneyNIiKi6sUgiky2Mk/mQ0kKguo0sksEvN2dcSEpA1tP/ZKYlYiIyNwYRJFNrcwrydvdBaO7Fs2NWrLjAgrZG0VERNWEQRSZLIiqjhxRpXnxsQg1lHgu8Q62nrphkWsgIiL7wyCKHli80XCeJfh4uOCle3Oj5keeY94oIiKqFgyiyKaH8/T++Hg9Nan90s1MfHmEWcyJiMj8GETRA9HpdBYfzhM13V3w6m8aqvsLv49RaReIiIjMiUEUPZCkOznIyS+EowMQ6uth0Wv5w6PhCPVxx/Xb2fjPz3EWvRYiItI+BlH0QPS9UBJAuThZ9uvk7uKECT0bq/vLdl1AenaeRa+HiIi0jUEUmSRHlCWH8ow93a42GjzkhVtZeVi555KlL4eIiDSMQRTZ/KRyY85OjpjUp4m6/9HeWNy4nW3pSyIiIo1iEEUPJCHVsukNStOnRTA6hPvhbl4B5v0v2tKXQ0REGsUgih5IXEqmug3394K1kK1npj/VXN3feOQqjiekWfqSiIhIgxhE0QOJT71rVcN5eq3r+GJwuzrq/qzNZ1QqBiIiIlNiEEVVlpWbj+SMHKsMosTkvk3g4eKEw3G3sPkENycmIiLTYhBFDzypXLZd8fF0gbUJ8nbHn59ooO6/szWaCTiJiMikGETRA++ZZ429UHpjutVXCTivpt3Fh7svWvpyiIhIQxhEkWbSG5SVgPPv/YsmmX/4w0VcTi6aCE9ERPSgGETRgwdRVpJosyz9WgXj8UYByM0vxLSvT3GSORERmQSDKNJ0T5Q+5cHsAS3h6uyIvTHJ+O4kJ5kTEdGDYxBFmg+iRESAF17pXjTJfNa3Z3CH++oREdEDYhBFVVJQqMMVK80RVZZXnmiAiFqeSLqTg39Gxlj6coiIyMYxiKIqSUzPRm5BIZwdHRDi4w5bIJPMZw1oqe5/ui8WJ64wkzkREVUdgyh6oKG82n4eatNfW9Gt8UP4fZtQFOqAyV+cUJPNiYiIqsJ2fvuRVbGFHFFlmfFUc9TyckX0jTv4YPcFS18OERHZKAZRpPlJ5SXVquGGmQNaqPtLd17A2evplr4kIiKyQQyi6IGCqHArzxFVlv6tQtCnRRDyC3VqWC+/gMN6RERUOQyiqEribLgnyjh3lOz7d/LqbazYe8nSl0RERDaGQRRVScK9ICrMRoMoEejtjum/K9oSZmFkDIf1iIioUhhEUaVJosrUzFyb7onSe7pdbfRsFqTSNUxYdwzZeQWWviQiIrIRDKKoyvOh/L1cUdPdBbZMhvXeHdwKATXccC7xDuZtO2fpSyIiIhthFUHUsmXLEBERAXd3d3Tq1AkHDhwot/6GDRvQtGlTVb9Vq1bYsmVLsedlg9np06cjJCQEHh4e6NmzJ2JiimeoTk1NxYgRI+Dt7Q1fX1+MHj0aGRkZhucvX76sfsGWLD///DPsnRaG8kqu1nvvmdbq/qqfYrHn/E1LXxIREdkAiwdR69evx8SJEzFjxgwcOXIEbdq0QZ8+fZCUlFRq/X379mH48OEq6Dl69CgGDhyoyqlTpwx15s2bh8WLF2P58uWIioqCl5eXOmd2drahjgRQp0+fRmRkJDZv3ow9e/Zg7Nix973f999/j+vXrxtK+/btYe8MK/M0EkSJ3zQNxMjO4er+6xuO49a94UoiIiKrDaIWLFiAMWPGYNSoUWjevLkKfDw9PbFq1apS6y9atAh9+/bFpEmT0KxZM8yePRvt2rXD0qVLDb1QCxcuxNSpUzFgwAC0bt0aq1evxrVr17Bp0yZV5+zZs9i2bRtWrlyper66du2KJUuWYN26daqesVq1aiE4ONhQXFxse/jKFOJsONFmeaY82QwNHvJSe+u9ufGE+i4RERGVxRkWlJubi8OHD2PKlCmGY46Ojmr4bf/+/aW+Ro5Lz5Ux6WXSB0ixsbG4ceOGOoeej4+PCpbktcOGDVO3MoTXoUMHQx2pL+8tPVeDBg0yHP/973+verAaN26MyZMnq8dlycnJUUUvPb1otVdeXp4qpqI/lynPWRlxKZnqNtTHzSzXYKn2OTsA859phSErovC/04lY9eMljHy0rlney9KfoblpvX320Ea2z/ZpvY15ZmxfRc9p0SAqOTkZBQUFCAoKKnZcHkdHR5f6GgmQSqsvx/XP64+VVycwMLDY887OzvD39zfUqVGjBubPn4/HHntMBVdffvmlGjaUYK2sQGru3LmYOXPmfce3b9+uetdMTYYiLSE6wUmmZOP6+ePYknjcbO9jqfb9LswBX112wj+2nEVm/CmE14Dm2lhdtN4+e2gj22f7tN7GSDO0LyuraMTFqoMoaxYQEFCsx+uRRx5RQ33vvfdemUGU9KgZv0Z6osLCwtC7d281gd2UEbJ8aXr16lXtw4uS2fu1qB0ycIoh/X6LEB93k7+HJdsnntTpkLnuOLafScL6hBr4+s+dVVJOLbXR3LTePntoI9tn+7Texjwztk8/kmTVQZQEKk5OTkhMTCx2XB7L/KPSyPHy6utv5ZiszjOu07ZtW0OdkhPX8/Pz1Yq9st5XyJBgeRGvm5ubKiXJh2uOL7C5zlueG3ey1FYprk6OqO1fA06ODmZ7L0u0T++9IW0RveRHNYl+yqYzWPF8e7U6U0ttrA5ab589tJHts31ab6OLGdpX0fNZdGK5q6urWu22Y4f0bBQpLCxUjzt37lzqa+S4cX0hgY2+fr169VQgZFxHIkqZ66SvI7dpaWlqPpbezp071XtLoFSWY8eOFQvM7HllXh1/D7MGUJYmPU8fjGingsXIM4lYuTfW0pdERERWxuLDeTL89cILL6hJ3h07dlQr6zIzM9VqPTFy5EjUrl1bzTcS48ePR/fu3dV8pf79+6sVdYcOHcKKFSvU89JbMGHCBMyZMweNGjVSQdW0adMQGhqq5jQJWdUnK/xkVaCsBpQuwXHjxqlJ51JPfPbZZyrIe/jhh9XjjRs3qhWDsqLPnumDKK2tzCtNy9o+mPa7Zpj29Wm8sy1aPe7coJalL4uIiKyExYOooUOH4ubNmyo5pkzqliE3ST+gnxgeHx+vJnbrdenSBWvXrlUpDN566y0VKMlk75YtWxrqyCo6CcQk75P0OEkKAzmnJOfUW7NmjQqcevTooc4/ePBglVvKmKRPiIuLU5POJbmn5LR65plnYM/sKYgSf3g0HIfibuHrY9fw6toj+GbcY6jjZx9tJyIiKw+ihAQzUkqze/fu+44NGTJElbJIb9SsWbNUKYusxJNgrCzSOyaFiovXaI6o8r5L7zzdGheSMnD6WjrGrj6ML1/pAg9XWaFIRET2zOLJNsm22FtPlJCAacXIDqjl5Yoz19Mx+Usm4iQiIgZRVNUgqpb9BFGitq+Hmmju7OiAb49fw4o9lyx9SUREZGEMoqjCbmfl4fbdPLvridLrVL8WZjzVXN1/d1s0dpwtnmqDiIjsC4MoqnQvVEANN3i6WsV0OotMNB/esS4KdcC4tUdx6uptS18SERFZCIMoqsJ8KA/YK7VoYUALPN4oAHfzCvDSpwdxNe2upS+LiIgsgEEUVVhcatHGw+G1vGDPXJwcsWxEOzQJqomkOzl46ZODSM/W5gafRERUNgZRVGEJ93qiwuxwPlRJ3u4uWDXqETxU0w3nEu/g1TVHkFdQaOnLIiKiasQgiio9nBfOIMqwYm/VC4/Aw8UJe2OSMWXjSaY+ICKyIwyiqMLiUuwzvUF5WtXxwdLnHoZsI/jF4Sv4x5azDKSIiOwEgyiqEBmqunZvArU9pjcoT49mQXhncGt1/6O9sfjwh4uWviQiIqoGDKKoQiSAkmX9bs6OCKzpZunLsTrPdgjD3/s1U/fnbTuHtVHxlr4kIiIyMwZRVLmhPH9Ptcyf7jemW338+YkG6v7fN53ElpPXLX1JRERkRgyiqELscc+8qpjUp4lKxinTosavO4qd0cxqTkSkVQyiqFLpDTipvHzSSzdnYEv0bx2CvAId/vTvI9h9LsnSl0VERGbAIIoqPZxH5XNydMDCoW3Rt0UwcgsKMfbfh7E35qalL4uIiEyMQRRVCIfzKp/VfPHwh9GreRBy8wvxx88O4acLyZa+LCIiMiEGUfSrJO+RIdEmh/MqzNXZEcuea4eezQKRk1+I0Z8dxL6LDKSIiLSCQRT9qltZecjIyVf36/gxiKp0IDWiHX7bNBDZeYVqw+IfznNoj4hICxhE0a/S90IFebvB3cXJ0pdjc9ycnfCBUSD1x88O4n+nuWqPiMjWMYiiXxWXkqluw/29LH0pNkuCz+V/aI/+rYpW7Y3//AQO3mS+LSIiuwuiLl68iKlTp2L48OFISipavr1161acPn3a1NdHVpTeIIyTyh94aE8mmw9pXwcFhTqsueCItQcSLH1ZRERUXUHUDz/8gFatWiEqKgobN25ERkaGOn78+HHMmDGjqtdBVowr80yb/uDdwa3x/KN1oYMDZnx7Fh/uvshNi4mI7CGIevPNNzFnzhxERkbC1dXVcPy3v/0tfv75Z1NfH1lRjiiuzDMNR0cHTOvXBD1rF6rH726Lxsxvz6jeKSIi0nAQdfLkSQwaNOi+44GBgUhO5vJtLeJwnnkymz9VtxBT+jZWjz/ddxnj1h5Bdl6BpS+NiIjMFUT5+vri+vX7N1Y9evQoateuXdnTkZXLyS/A9fRsdZ/Deab30mMRap6Uq5Mjtp66gZEfH0BaVq6lL4uIiMwRRA0bNgxvvPEGbty4of6aLiwsxE8//YTXX38dI0eOrOzpyMpduXVXbabr6eqEgBq/DN+S6fy+TSg+e6kjaro748DlVDyzfD+upt219GUREZGpg6h//OMfaNq0KcLCwtSk8ubNm6Nbt27o0qWLWrFH2p1ULkEzmUfnBrWw4U+dEeztjgtJGRi47Cccjb9l6csiIiJTBlEymfyjjz7CpUuXsHnzZvznP/9BdHQ0/v3vf8PJiYkYtYbzoapP02BvbPxzFzQNrombd3IwdMXP+PrYVUtfFhERmSqImjVrFrKyslRPVL9+/fDss8+iUaNGuHv3rnqONLoyj0FUtQj19cAXr3RR++3JxsXj1x3D/O3nUMiVe0REth9EzZw505AbypgEVvIcaXQ4j+kNqk0NN2f86/kOeLl7ffV4yc4LeHXtEWTlFu1fSERENhpESVLA0ubGSLJNf39/U10XWQkO51kuKeeUJ5vh/SFtDCv3hizfb/g8iIjI8pwrWtHPz08FT1IaN25cLJAqKChQvVN/+tOfzHWdZAESMOt7ojicZxnPtK+DiFqeePnfh3H6WjqeWvojFg17GN0bP2TpSyMisnsVDqIWLlyofqm+9NJLatjOx8en2GTziIgIdO7c2VzXSRaQnJGLrNwCSLxc28/D0pdjtzpE+OObv3TFK/85jBNXbuPFTw7gbz0bY9xvGqrs50REZOVB1AsvvKBu69Wrp9IZuLi4mPO6yAroe6FCfTzg5syVl5ZU29cDn7/cWW0P898D8VgQeR7HEtLwz2fbwseTP4tERDYxJ6p79+6GACo7Oxvp6enFCmlHfGqmug3zZy+UNXB3ccLcp1th3jOt4ersiJ3RSWp47/S125a+NCIiu1TpIEpW4Y0bN07tlefl5aXmShkX0o74lKKs2dzuxbo82yEMG1/pgjp+Hqq3cNCyffhs32U13E5ERFYcRE2aNAk7d+7Ehx9+CDc3N6xcuVLNkQoNDcXq1avNc5VkEYZJ5bW8LH0pVELL2j7Y/Jeu6NE0ELkFhZjxzWmM/fdh3MrkvntERFYbRH377bf44IMPMHjwYDg7O+Pxxx9X273IdjBr1qyp0kUsW7ZMTUx3d3dHp06dcODAgXLrb9iwQW09I/VbtWqFLVu2FHte/iKfPn06QkJC4OHhgZ49eyImJqZYndTUVIwYMQLe3t5qU+XRo0eXmv9KXLhwATVr1lT17HM4jz1R1sjX0xUrX+iAGU81V2kQIs8kot/ivYi6lGLpSyMisguVDqIk+KhfvygJoAQg8lh07doVe/bsqfQFrF+/HhMnTsSMGTNw5MgRtGnTBn369EFSUlKp9fft24fhw4eroOfo0aMYOHCgKqdOnTLUmTdvHhYvXozly5cjKipKDTvKOWUOl54EUKdPn0ZkZKTavkaufezYsfe9X15enno/CRbted88sk6SamTUY/XUdjH1Arxw/XY2hn/0M/4ZeR4FzHJORGRdQZQEULGxseq+9AZ9/vnnhh6qqvTULFiwAGPGjMGoUaPUZsYS+Hh6emLVqlWl1l+0aBH69u2rhhWbNWuG2bNno127dli6dKmhF0rSMUjv2IABA9C6dWs1zHjt2jVs2rRJ1Tl79iy2bdumhiKl50sCwCVLlmDdunWqnjE5j7RTtrexJ9l5BUhMz1H3mSPKdob3BrerA4mdFu2IwbP/2o/LyUW9iUREZMEUB3oS7Eh2clml9+abb+Kpp55SAYz02EhAVBm5ubk4fPgwpkyZYjjm6Oioht/2799f6mvkuPRcGZNeJn2AJAHejRs31Dn0JKeVBEvy2mHDhqlbCfg6dOhgqCP15b2l52rQoEHqmMz9kqHDY8eOYePGjb/anpycHFX09KsV5f+NFFPRn8uU5yzpUlKGYQsSLxfzvpcl2mdp5mijqyPwzqDm6FzfD29/exaH427hyUV78EafxniuY1ipOw2YCz9D28f22T6ttzHPjO2r6DkrHUT97W9/KxZ4REdHq0CoYcOGqtenMpKTk1W286CgoGLH5bGctzQSIJVWX47rn9cfK6+OrC40JvO7ZNsafZ2UlBS8+OKL+M9//qOGLSti7ty5pe4fuH37dtW7ZmoyFGkup27JL1wn+DjlYevWrbAEc7bPWpijjZKA5LUWwNoLjohJB97eHI11e89geINC+LqhWvEztH1sn+3TehsjzdA+yURg8iBKIjMZSpMht0aNGqlj4eHhqmiNDDE+99xz6NatW4VfIz1qxr1k0hMVFhaG3r17VzgQq+jnIF+aXr16mS3padL+OCD6HFpGBKFfv7aoTtXRPkurjjY+V6jDv6Pi8d72GETfBuafccX03zXD71sHm71Xip+h7WP7bJ/W25hnxvZVNO9lpYIoucgTJ07AVAICAuDk5ITExMRix+VxcHBwqa+R4+XV19/KMVmdZ1ynbdu2hjolJ67n5+erSfL618tQ3jfffIP333/fMNeqsLBQ9VitWLFCbX9TkqR8kFLa/zdzfIHNdV5xNa1oWDIioIbFfvjM2T5rYe42/rFbQzzRNBivfX4Mx6/cxutfnMT/ziRh9oCWCPZxh7nxM7R9bJ/t03obXczQvoqer9ITy//whz/g448/hinInnvt27fHjh07DMckUJHHZe3DJ8eN6wuJRPX1ZVsaCYSM60hEKXOd9HXkNi0tTQ1D6knQJO8tc6eEzJuSuVD6MmvWLJXmQO7r50xpWcK9lXlMb2D7GgbWwJevdMHEXo3h4uSgUiH0WvAD1kTFoZAr+IiIqqzSc6Kkx0ZWzn3//fcqAJL0AcYqO7lchr9kXz6Z5N2xY0e1si4zM1NNYBcjR45E7dq11XwjMX78eDWpff78+ejfv79aUXfo0CHVOyRkmGLChAmYM2eOGnKUoGratGkqGaikQhCyqk+GJWXIToYmpUtQsrDLpHOpp69jTN5DJp63bNkS9iDOkGiTQZQWODs54q89GqFPi2C88eUJte/e3786ha+PXVNbyTR4qIalL5GISPtBlORjkpQC4vz588Weq8o8i6FDh+LmzZsqOaZM6pYhN0k/oJ8YHh8fr4IXPdn8eO3atSr1wFtvvaUCJVmZZxzcTJ48WQVikvdJepwkhYGcU5Jz6kliUAmcevTooc4vyUMltxRJb6DO0BPFHFHa0iS4puqVkm1i3vvfORyITcWTi/ZifI9GGNutPlycKt05TURktyodRO3atcvkFyHBjJTS7N69+75jQ4YMUaUsEszJ8JuUsshKPAnGKkpW6kmxBzczcpCTXwgnRweE+nLzYa2Rz/WlrvXQq3kQ/r7pFPacv6kCqm+OXcOsAS3QqX4tS18iEZFN4J+ddJ+4lKJeqFBfd/ZMaJjMd/ts1CP459A28PN0wbnEOxi64mf8bf0xJN35Jbs/ERGVjr8h6T7c7sV+SK/toIfrYOdrT2B4x7qQEfmvjl5Fj/d/wCc/xSK/oNDSl0hEZLUYRNF9GETZHz8vVzXB/Ks/P4bWdXxwJycfM789g98t+RGHLhftj0lERMUxiKL7xKcU7bdW17/4ykvSvrZhviqQ+r9BLeHj4YLoG3fwzPL9+Ot/j+LKrYpl8CUishcMoug+7ImybzLxfESncOx6/QkM7SB77gHfHL+GHvN/wHv/i0ZGTr6lL5GIyDZX50kW77LmVkgKAdlDT3Izke2KT72rbhlE2Td/L1e8+0xrPN85HLM3n0FUbCqW7bqI9Qev4PXejTGkQ5gKuIiI7FWlgyhJWCkBk2yDYkx/TG4lL5PkbvLz8zPltVI1yMzJR3JG0ZYvdZlokwC0rO2DdWMfxfYziZi75Swup2ThzY0n8em+y5javzm6Ngqw9CUSEdnGcJ5ssfLII4+o29u3b6si92W7lM2bN2PPnj1ISUnB66+/bp4rJrNKuDfvRebDSCES8seRZDvf/rfumNq/GbzdndV8qT98HIXnP47CySu3LX2JRETW3xMl267IFiuSOVxPsn7LUJ5kCD99+rTauqW0DXrJ+sXfyxHF7V6oNK7Ojvjj4/UxuF0dLNoRg//8HIe9McnYG/Mj+rUKxmu9m3ALGSKyG5Xuibp48SK8vb3vOy7HLl26pO7LVizJycmmuUKyyKRybjxMv5YS4e3ft1D5pQY9XFtNPt9y8gZ6/3MP3vzyBK7fZrJOItK+SgdRsunwpEmT1H53enJf9quTYT4RExODsLAw014pVQuuzKPKkHlz/xzaFlvHP46ezQJRUKjDuoMJ6LnwR3x12REpmbmWvkQiIusJoj7++GPExsaiTp06aiWeFLl/+fJlrFy5UtXJyMhQGwST7QZR4QyiqBKaBntj5QuP4MtXOqNTPX/k5hdi93VH/Gb+Hvxjy1ncvFO0WIGIyK7nRDVp0gRnzpzB9u3bcf78ecOxXr16wdHR0bCCj2x7ThR7oqgq2of7q5V8u87ewIwvDyMhsxAr9lzC6v2XVe6pl7vXR2BNd0tfJhGRZYIoIcFS3759VSHtkKGYK7eKckRxThQ9yEq+xxsF4LVWBajR6BEs3R2LYwlp+PjHWDURXfboe+WJBgjyZjBFRHYYRO3YsUOVpKQkFBYW36B01apVpro2qmaJ6dnILSiEs6MDQn09LH05ZONksnn3xg+hR/MQ7IlJxqLvz+NIfJrKL7X2QLzKhj62W30G7ERkP0HUzJkzMWvWLHTo0AEhISHqr07Shrh7Q3l1/DyYiZpMRv6NkGCqW6MA/HQhBYt2nMfBy7fw75/jVDDVv1WIGuZrEepj6UslIjJvELV8+XJ8+umneP755yv7UrJyCUxvQGakdjNoFIDHGtbC/ksp+HD3RZVjSvblk9Kt8UP4U7f66NygFv84IyJtBlG5ubnFEm2SdsSlZqpbJtokc5IAqUuDAFVOXb2Nf+25hO9OXMOe8zdVaVPHBy93b6AypLNHlIg0leLgj3/8I9auXWueqyGL4sbDZIl9+ZYMfxg/TPoNRnYOh7uLI45fuY0/rzmC387fjVU/xuJOdp6lL5OIyDQ9UdnZ2Wrbl++//x6tW7eGi0vx/dUWLFhQ2VOSlWCiTbIUGUKeNaAlxvdohM/2x6mUCDJHb9bmM1gQeR7PtK+DF7tEICLAy9KXSkRU9SDqxIkTaNu2rbp/6tSpYs9xHoNti08pGs6r689fVGQZtWq4YWKvxvhT9/rYeOSqWsl3ISlD3X62/zJ6NA3EqMfqoQvnTRGRLQZRu3btMs+VkEWlZ+fhVlbRsEmYP9MbkGV5ujrjD4+GY0Snumry+aqfYrH73E18fzZJlSZBNfHiYxEY0DZU1SUisgT+60PFVub5e7mipnvxIVoiS5HeJlm1J+XizQx8tu8yvjh8BecS72DKxpP4x3dn8XS72niuUziaBNe09OUSkZ2pUBD19NNPq7QG3t7e6n55Nm7caKpro2rE7V7I2jV4qIaaN/Va7ybYcChB5ZmSeVMyh0rKIxF+amuZvi2D4e7iZOnLJSI7UKEgysfHxzD/QO6T9nBSOdkKHw8X/PHx+njpsXr46WIy1vwcj8iziSqBpxS/b13URHTpnarHiehEZOkg6pNPPin1PmkHgyiyNY6OskffQ6rIlkXrDybgvwficf12Nj7aG6uKTEB/tkMYe6eIyCw4J4qKB1FMtEk2SDYz/muPRvjzEw3UBPQ1UXHYff4m9l1MUaXmJmc81TYUQ9rXQdswX67sIyLLBFGJiYl4/fXXDRsQ63S6Ys8XFBSY5sqoWrEnirTA2ckRPZsHqSKLJWQSupSraXexNipelUaBNTCkQx0MergOHqrpZulLJiJ7CqJefPFFxMfHY9q0adyAWCPyCwpx9RazlZP2Enj+rVdjlcDz50sp2HD4Craeuo6YpAz8Y0s03t12Dr9pEqgCKrl1da70Bg5EZOcqHUT9+OOP2Lt3ryHhJtk+mUOSX6iDq5Mjgr3dLX05RCafO9WlYYAqMwe0wObj17HhcAKOxqfh+7OJqshk9X6tQjCwbSgeifBXryEiMnkQFRYWdt8QHmljKK+Ovwd/eZCmebu74LlOdVW5kHQHGw5dwaZjV5GYnqMmpUup7euBp9qEYuDDoWga7G3pSyYiK1bp/uuFCxfizTffxOXLl81zRWSxICqcQ3lkRxoG1sSUfs2w780eWPvHTni2Qx3UdHNW86eW/3ARfRfuRd+Fe/Dh7ovqGBHRA/dEDR06FFlZWWjQoAE8PT3v24A4NTW1sqckC5OEhYLzocgeORkN90kyz13RSap3alf0TUTfuIPobTJ/KhodI/zRr1UwnmwVolYDEhE5V6UnirS55YtMxCWyZ5JLSoIkKbez8tREdAmoomJTceByUZm5+Qw6hPuhT/NAuORY+oqJyKaCqBdeeME8V0KWH86rxezORHo+ni4Y1rGuKtdv38WWkzew5eR1HI4ryowuRf4J/Sb5APq3DsWTrYIR4sPNu4nsyQMl28zOzkZubm6xY7K/HtmWuJRMdcvhPKLSSXA0ums9VSSg2nryBr47cQ2H49MMZdbmM2hX11et8uvTIpg9u0R2oNJBVGZmJt544w18/vnnSElJue95Jtu0LTJkkZ6dr+6H+fOvaKKKBFQvda2H5zvVwdqvtiA3uAX+dzoJh+Ju4Uh8mipzvjuLpsE10bt5EHq3CEaLUG/m1CPSoEqvzps8eTJ27tyJDz/8EG5ubli5ciVmzpyJ0NBQrF69ukoXsWzZMkRERMDd3R2dOnXCgQMHyq2/YcMGNG3aVNVv1aoVtmzZUux5ScEwffp0lQzUw8MDPXv2RExMzH0T4EeMGKF6znx9fTF69GhkZGQYnj937hx+85vfICgoSL1P/fr1MXXqVOTl5UGLQ3mSudnTlbsAEVWGrxvwYudwfPFKF/w8pQdmPNUcj9b3V5PVZVL64p0X8LslP+Kxd3Zixten8GNMMvIKCi192URkqSDq22+/xQcffIDBgwfD2dkZjz/+uAou/vGPf2DNmjWVvoD169dj4sSJmDFjBo4cOYI2bdqgT58+akuZ0uzbtw/Dhw9XQc/Ro0cxcOBAVU6dOmWoM2/ePCxevBjLly9HVFQUvLy81Dll+FFPAqjTp08jMjISmzdvxp49ezB27FjD87LqcOTIkdi+fbsKqGRC/UcffaSuU0viUjmUR2QKwT7uGPVYPawb2xmH/t4T84e0Qd8WwfBwccK129n4bH8c/vBxFNrPjsT4dUfx3YnryMgp6gUmIttU6a4H6cGRXhkhvTj6lAZdu3bFK6+8UukLWLBgAcaMGYNRo0apxxL4fPfdd1i1apXKR1XSokWL0LdvX0yaNEk9nj17tgqEli5dql4rvVAS8EhgN2DAAFVHesikR2nTpk0YNmwYzp49i23btuHgwYPo0KGDqrNkyRL069cP77//vupVkzbq2ynCw8Oxe/dula1dS7hnHpHp+Xm5YnD7Oqpk5xXgpwvJiDxTlB09OSMXXx+7poqLk4PKkP7bpoF4okkgGjzkxWE/Ii0HURJYxMbGom7dumpITeZGdezYUfVQybBYZcik9MOHD2PKlCmGY46Ojmr4bf/+/aW+Ro5Lz5Ux6WWSAEnItd24cUOdQ8/Hx0cNE8prJYiSW7lWfQAlpL68t/RcDRo06L73vXDhggq8nn766TLbk5OTo4peenq6upUhQFMOA+rPZYpzxiUXDWHW8XWzmqFKU7bPWmm9jVpvX2Xa6ASgW0N/Vd7+XVMcv3Ib359NUiU2JQv7LqaoIvOo6vh54InGAejeOACdIvzh4Sqvtgytf4Zab589tDHPjO2r6DkrHURJj9Hx48fRvXt31VP01FNPqV4geUPpVaqM5ORkNRFdeomMyePo6OhSXyMBUmn15bj+ef2x8uoEBgYWe16GJv39/Q119Lp06aKGGSU4kuG+WbNmldmeuXPnqvlhJcmQoCQmNTXpgXtQR87LiK4jUhNisGXLeVgTU7TP2mm9jVpvX1Xb2FJKYyDpLnA2zQFnbjngQroDrty6i/9EJaji4qBDQx8dmvvq0NxPhwAL5ffU+meo9fbZQxsjzdA+SSpuliDqb3/7W7HeGwl2pDepYcOGaN26NbRG5mzduXNHBY4yhCjDfTK5vjTSo2bcSyY9UbLXYO/evU2a+kECVvnS9OrV676M8ZX13tk9kqwCv3viUZVA0BqYsn3WSutt1Hr7zNHGrNx87L+Uih/OJ6si86gkwDqbBnx5Gagf4InHGgbgsQb+6FTPHzXczLsQROufodbbZw9tzDNj+/QjSb/GubIXLPORZO5Ro0aNDHOFpFRFQEAAnJyckJiYWOy4PA4ODi71NXK8vPr6Wzkmq/OM67Rt29ZQp+TE9fz8fDW/q+T7ShAkmjdvrnrNpDfqtddeU9ddkqxWlFKSfLjm+AI/6Hlz8wvVP9SiQaC31f2Qmev/mzXRehu13j5TttHHxQV9W9VWReZ2xiRlqC1odkYXpU+4lJyFS8nx+PfP8XB2dEC7un7o2ihAlda1feDsVOl1QhWi9c9Q6+2zhza6mKF9FT2fY2VPeuLECZiKq6sr2rdvjx07dhiOFRYWqsedO3cu9TVy3Li+kEhUX79evXoqEDKuIxGlzHXS15HbtLQ01YOmJ2kb5L1l7lRZ5HkJJOVWC66l3UWhDnBzdlQpDojIOsjk8sZBNfFy9wZY/3JnHJ3eC8v/0A4jOtVVi0DyC3VqC5oFkefx9Af78PDsSLz870P4989xhuS5RGR+le4P/sMf/oCPP/4Y77zzjkkuQIa/ZCsZmeQtE9RlZZ0k9NSv1pM0A7Vr11bzjcT48ePVfKz58+ejf//+WLduHQ4dOoQVK1YY/vGZMGEC5syZo3rLJKiaNm2aWnEnqRBEs2bNVI+arAqUXjUJjMaNG6cmnUs9IekaJGiUPFTSuyTvIcN1sgGzViJ645V5XBFEZL283V3Qt2WIKiI+JQt7L9xUeadk5Z8kzP3f6URV9IlzuzZ8CJ0b1FJ5qwJrcsNkIqsIomTYS9IPfP/996oXSXIwGavs5HIJSm7evKmSY8qkbhlyk1Vw+onh8fHxatWc8UTvtWvXqhQGb731lgqUZGVey5YyVbOIzFmSQEyG3qTHSdIvyDklaaaeBEkSOPXo0UOdX/JeSW4pw/8YZ2e8++67OH/+vOpalyFLqW88J8zWxRn2zGN6AyJbUreWJ0bUCseITuEoKNTh5NXb2Hv+JvZeSMbR+FtISL2L/x6IV0U0DKyhgqnO9QPQqb4/Amqw55nIIkGUJLVs166dui8BhrGq9mZIcCKlNJKbqaQhQ4aoUha5DllFV95KOlmJJ8FYecGdFC1LuBdEcY8vItsl2dHbhvmq8pcejZCZk4+o2BT8GJOCny+l4OyNdFxIylDlPz8XBVWNgySoqoXO9WuhU/1a8PdytXQziOwjiNq1a5d5roSqnQwJCCbaJNIOLzdn/LZpkCoiLSsXUbGp2H+xKKiS7WjOJ2aosnp/nKoj+/xJUCW9Ve3D/TlHkqiCqrxGVpJPXrx4Ed26dVP708mQF+fV2BYO5xFpn6+nK/q0CFZFpGbmIupSUUC1/1KKCqYksJLy6b7Lqk79AC+0q+sLl9sOaJ6SiYZBPvz3ncgUQVRKSgqeffZZ1SMlP1Sysa9kMZe97Pz8/NSEb7J+EvTqh/PYE0VkP2To7slWIaqI5IwcRF1Kxf5LyTgYewvnEu/gUnKmKpJv/b8Lf1JzqB6J8EOHCH912zzE22wpFYhsSZWSbcrqNJnwLavc9GT+kKy0YxBlG25l5Rk2P63jxyCKyF5JgNS/dYgq+uG/I/G3EHUxBZHHLiEhy1EFWltP3VBFeLo64eG6vugQLkGVP9rW9TV78k8ia1Tpb71sYfK///0PderUKXZcVsnFxRWNr5P10+eSCfZ2h7uL5fbnIiLrG/6T+VSPN/BH8/wY9OjVE2eTsnDwcioOXb6FQ5dTVUqFny6kqCJkpK9JUE0VWD0c5qduGzxUA46OHAIkbat0ECWpA0rbB06yfZeWrZusP0cUEVFZ3FycVG+TFFFYWJRNvSioSsXBy7dwNe2uYV7Vfw8kqHo13ZxVD9XDYb54uK6fWj3ox1WAZO9B1OOPP47Vq1dj9uzZ6rHMi5IM3vPmzcNvfvMbc1wjmQHTGxBRVUjvUpPgmqr84dGiLb+S0rNxNCENR+Ol3MKJK7dxJycfe2OSVdGrF+B1L6iSlAx+aBpSEy6cW0X2FERJsCQJKiWDd25urkpsefr0adUT9dNPP5nnKsnk4u6lN+DKPCJ6UIHe7sVWAOYXFKoJ6kVBVRqOJtzCpZuZiE0uKhuPXlX1XJ0d1ST11nV80Kq2D1rX8VWJQSX3FZEmgyjJDC5JNpcuXYqaNWsiIyMDTz/9NF599dViG/6SdeNwHhGZi6zcaxHqo4q+t0omrB/T91YlpOFY/C01t0qOSdHzcHFCy9reaFXbtyi4quODerW8OL+KrFKVllP4+Pjg73//e7FjV65cUdus6PewI+tmSG/AnigiqqYJ6080CVRFP7dK/pg7cfU2TiSkqdvTV28jM7dAzbOSoicr/ySwkp6qoh4rH+75SVbBZGtSJX+UbEzMIMr65eQX4Hp6trrPnigisgTpWYoI8FLl922KNn6XfQBjkzPUnCopsifg6Wu3VTqWny+lqqJX091ZDQVKb1fzULn1VkOBnGNF1YmJPezQlVt3odMV5XqpxdUyRGQlZC5Uw8Caqjzdro5hftWFm0WB1UkJrq7extlr6biTLXsEpqqi5+rkiMbBNYoFV81CvJnDisyG3yw7nw/F7nAisvb5VU2DvVV5tkOYOpabX6g2VD5zPV31VJ25lq7uS2B16mq6KsAVwzkiankagqqiAMsbvu7ssaIHxyDKDnHjYSKyZWpVnwREod54pn0dw1ZW0suuD6pO3wusrt/OxuWULFW+O3ndcA5/LxfUcnLEEUSjeagPmgR7o3FQDXi68tciVVyFvy2yAq88aWm/rK4g68aVeUSkNdKrLnnvpPRt+ctKcdlwuainSuZXpav7F29mIDUzD6lwRMz+eKNzFP27KNnXm6pcWN4qH5b0ZHGvQHqgIEpW5P3a8yNHjqzo6cgKgijmiCIie9hwuWujAFX07uYW4Oy1W9gQuQ/uQfURk5Spsq3LHoGSQ0/K9jOJxXq+GgXWUAGVPriS28CabpwSYecqHER98skn5r0SqvbhPGYrJyJ75OHqpFIlJATq0O/JJnBxcVHHUzJycO7e9jXqNvEOzt+4g7t5BaoXS4oxHw8XFVw1Cqqh9gpsFFRTPQ7xcWdwZSc4+GtnZN4Ah/OIiO5Xq4YbujSU8kuvleSzSriVZQisioKsdJV5/fbdPByKu6WKMS9XJ5VuQVYZSoAlgZU8ruPnyWzsGsMgys7czMhRf1XJH0nyA01EROXnswqv5aWKflsbkZ1XoLayiUm6g4tJGWpTZimXkzNVwtDjV26rYszN2fFej1UNNNTfBtZUUyuY38o2MYiy00zloT4eapyfiIgqz93FybBC0JikX4hLyVQpGPSBVUziHVxKzkROfqFaMSjFmLOjg9o9on5ADdR/yAv1A7xQ/6Gi+5LLj0OD1otBlJ3RD+WF+XtY+lKIiDRHTUKXuVFBNfGk0XHJxi5/xBYFVndUkKUvWblFvVpScLb4+bzdnVHvoRpooAKrouCqXoCXKhLIkWUxiLIzsupEhPt7WfpSiIjshpPRNje9mgcVm3N1Iz27KIhKzrh3KwFVBq6m3VWbNB9PSFPFmHROyYiCBFYyRFjPKMgK8Xbnhs3VhEGUnTFMKmd6AyIii5NgJ9TXQxXjNAz6eVeXUzIRey+wkvxWMqFdAi2Z1C5BlpS9Mcn39YbJwqG6fh4oTHfErah41A/0RkQtL4T6ujPnlQkxiLLTOVFMb0BEZN1kuE6/5U3JVdaSRFQCKwmwLup7sG5mqD+U9dviSAEcsXtzdLH5V3X8PNREeUkiqm4Dim7D/Dw5V7aSGETZ7XAegygiIlskE80lHYOURyL8iz0nc6+upd1V/9ZfTErH7kOn4eQThPhbRcdkcrt+G5wfSpxXRgClR0x6rGTFYFEpui8Blhc3cr4P/4/YEcnSm3QnR91njigiIm3OvdJvf9Mpwge+ySfRr9/DKqGozL9KvJONy8mSlT1TBVLGtzLBXfYflPLjhdKzv4f5eRjOH+Yntx7q94kEX/aYpoFBlB25cquoF6qmmzN8PYsy9BIRkf3Mvwrx8VClc4Na9w0RSh5B6a2SXFdq+5vUovsyRChzsGQIUUrJ/Ff6Xiw5rwwVSlBVFGh5qEBLHj+k0S1yGETZ4VCeTCrX4peZiIiqRn4nBNZ0V6XkEKFIz85Tc2oTUu8W3d6S+3Jb9FiGCfUT3aNiU+97vSQalQBLgisVZPl5qse1pfh6qF4uW/y9xCDKjnC7FyIiqgpvdxe0CPVRpSSd9GLdybkXWBUFVfL7Rv/4+u27Ksi6KJPgJRdWKTxcnNTKwdp+niqoUgGW7y9BVpC3u1VumcMgyo4wiCIiIrP0Ynm7q9I+/P7n8woK1WR3FWAZ9WDJFJOrt+6qubqyHVl5QZasKgyRIEsCK19PFVwF13TFldsO6JFfiHt7SFc7BlF2hDmiiIiourk4ORr2HyxNTn4BrqdlFw0HSnB17/ZqWpY6Js/lq4zvRYEYYDxc6IQ/5hfAUhhE2RH2RBERkbVxc3YyZHMvjaRtSLqTrVYNFgVXRSsIr6RmIu56Mmq6W26hFIMoOyFLW/WJNrnlCxER2Qono1WFj0T8cjwvLw9btmyx5KXB/pI62CkZc5aJferL6Otu6cshIiKyeQyi7GwoT1Y/2GNCNCIiIlPjb1M7C6I4lEdERGQaDKLsRHxK0bJRbjxMRESkoSBq2bJliIiIgLu7Ozp16oQDBw6UW3/Dhg1o2rSpqt+qVav7JpZJ4q/p06cjJCQEHh4e6NmzJ2JiYorVSU1NxYgRI+Dt7Q1fX1+MHj0aGRmy43WR3bt3Y8CAAeocXl5eaNu2LdasWQNbxZV5REREGgui1q9fj4kTJ2LGjBk4cuQI2rRpgz59+iApKanU+vv27cPw4cNV0HP06FEMHDhQlVOnThnqzJs3D4sXL8by5csRFRWlgiA5Z3Z2tqGOBFCnT59GZGQkNm/ejD179mDs2LHF3qd169b48ssvceLECYwaNQojR45UdW16OI85ooiIiLQRRC1YsABjxoxRQUrz5s1V4OPp6YlVq1aVWn/RokXo27cvJk2ahGbNmmH27Nlo164dli5dauiFWrhwIaZOnap6kiQQWr16Na5du4ZNmzapOmfPnsW2bduwcuVK1fPVtWtXLFmyBOvWrVP1xFtvvaXO3aVLFzRo0ADjx49X77tx40bYIvZEERERaShPVG5uLg4fPowpU6YYjjk6Oqrht/3795f6GjkuPVfGpJdJHyDFxsbixo0b6hx6Pj4+KliS1w4bNkzdyhBehw4dDHWkvry39FwNGjSo1Pe+ffu2CtzKkpOTo4peenq6IZeFFFPRn6ui58zMyUdyRq66H1LTxaTXYg6VbZ8t0nobtd4+e2gj22f7tN7GPDO2r6LntGgQlZycjIKCAgQFBRU7Lo+jo6NLfY0ESKXVl+P65/XHyqsTGBhY7HlnZ2f4+/sb6pT0+eef4+DBg/jXv/5VZnvmzp2LmTNn3nd8+/btqnfN1GQosiKuqTnlzvB01uHHXRV7jTWoaPtsmdbbqPX22UMb2T7bp/U2RpqhfVlZRaM3v4YZyytg165darjxo48+QosWLcqsJz1qxr1k0hMVFhaG3r17qwnspoyQ5UvTq1cvuFRg18XIM0nAiWNoEOSDfv0ehbWrbPtskdbbqPX22UMb2T7bp/U25pmxffqRJKsOogICAuDk5ITExMRix+VxcHBwqa+R4+XV19/KMVlZZ1xHVtjp65ScuJ6fn69W7JV83x9++AFPPfUU/vnPf6qJ5eVxc3NTpST5cM3xBa7oea+lFw0x1q3lZVM/SOb6/2ZNtN5GrbfPHtrI9tk+rbfRxQztq+j5LDqx3NXVFe3bt8eOHTsMxwoLC9Xjzp07l/oaOW5cX0gkqq9fr149FQgZ15GIUuY66evIbVpampqPpbdz50713jJ3yjjNQf/+/fHuu+8WW7lna+JS9Ik2OamciIjIVCw+nCfDXy+88IKa5N2xY0e1si4zM1MNnwnp/aldu7aabyRklVz37t0xf/58FeDIirpDhw5hxYoV6nkHBwdMmDABc+bMQaNGjVRQNW3aNISGhqpUCEImh8tKO1kVKKsBpUtw3LhxatK51NMP4f3ud79T7zd48GDDXCkJ/GTulC3hyjwiIiINBlFDhw7FzZs3VXJMCVRkyE3SD+gnhsfHx6tVc3qScmDt2rUqhYGkIZBASVbmtWzZ0lBn8uTJKhCT3iPpcZIUBnJOSc6pJ4kzJXDq0aOHOr8ESpJbSu+zzz5TE8skeNMHcEICOOmhsiUJDKKIiIi0F0QJCWaklKa0gGXIkCGqlEV6o2bNmqVKWaQ3SYKxsnz66aeq2LqCQh0Sbt0Lophok4iISDvJNsm8bqRnI69AB2dHB4T4eFj6coiIiDSDQZTGxd+bVF7HzwNOjg6WvhwiIiLNYBClcfGpmYb0BkRERGQ6DKI07peVeRzKIyIiMiUGURoXn3pX3XJlHhERkWkxiNK4+JR7w3n+HM4jIiIyJQZRGsdEm0RERObBIErD0rPzcCsrT91njigiIiLTYhBlB+kNanm5ooabVeRVJSIi0gwGURqm3+4ljEN5REREJscgyg7mQ4VzKI+IiMjkGERpWBwnlRMREZkNgygN43AeERGR+TCIsofhPAZRREREJscgSqPyCwpx9da9bOWcE0VERGRyDKI06vrtbOQX6uDq7Iigmu6WvhwiIiLNYRCl8aG8MD8PODo6WPpyiIiINIdBlEbF3Uu0yZV5RERE5sEgSqO4Zx4REZF5MYjSqPjUTHVbt5aXpS+FiIhIkxhEaRR7ooiIiMyLQZTGNx9mEEVERGQeDKI0KC0rF+nZ+eo+gygiIiLzYBCl4aG8h2q6wcPVydKXQ0REpEkMojSI86GIiIjMj0GUhnNEcc88IiIi82EQpUEJ+mzlDKKIiIjMhkGUBnE4j4iIyPwYRGl5OK8WgygiIiJzYRClMbn5hbh++666z54oIiIi82EQpTHX0u6iUAe4uziqFAdERERkHgyiNCbOaD6Ug4ODpS+HiIhIsxhEaQwnlRMREVUPBlEaTW9Q19/L0pdCRESkaQyiNCYuJVPd1vX3sPSlEBERaRqDKI2JT723Mo/pDYiIiMyKQZSG6HQ6DucRERHZSxC1bNkyREREwN3dHZ06dcKBAwfKrb9hwwY0bdpU1W/VqhW2bNlyXyAxffp0hISEwMPDAz179kRMTEyxOqmpqRgxYgS8vb3h6+uL0aNHIyMjw/B8dnY2XnzxRXV+Z2dnDBw4ELYgNTMXGTn56n4dPw7nERERaTaIWr9+PSZOnIgZM2bgyJEjaNOmDfr06YOkpKRS6+/btw/Dhw9XQc/Ro0dVcCPl1KlThjrz5s3D4sWLsXz5ckRFRcHLy0udUwIjPQmgTp8+jcjISGzevBl79uzB2LFjDc8XFBSoAOyvf/2rCsJsbWVesLc73F2cLH05REREmmbRIGrBggUYM2YMRo0ahebNm6vAx9PTE6tWrSq1/qJFi9C3b19MmjQJzZo1w+zZs9GuXTssXbrU0Au1cOFCTJ06FQMGDEDr1q2xevVqXLt2DZs2bVJ1zp49i23btmHlypWq56tr165YsmQJ1q1bp+oJCbw+/PBDdW3BwcGwufQGnA9FRERkds6wkNzcXBw+fBhTpkwxHHN0dFQ9P/v37y/1NXJceq6MSS+TPkCKjY3FjRs3ivUe+fj4qGBJXjts2DB1K0N4HTp0MNSR+vLe0nM1aNCgKrcpJydHFb309HR1m5eXp4qp6M9V8pyxN4uGJOv4upv0/apbWe3TEq23Uevts4c2sn22T+ttzDNj+yp6TosFUcnJyWrYLCgoqNhxeRwdHV3qayRAKq2+HNc/rz9WXp3AwMBiz8u8J39/f0Odqpo7dy5mzpx53/Ht27erHjZTk+FIY/svSMeiI7KTE7BlSzxsXcn2aZHW26j19tlDG9k+26f1NkaaoX1ZWUUjO1YbRGmR9KoZ95RJT1RYWBh69+6tJrGbMkKWL02vXr3g4uJiOL7m44PAzVvo0akt+rUJga0qq31aovU2ar199tBGts/2ab2NeWZsn34kyWqDqICAADg5OSExMbHYcXlc1jwkOV5eff2tHJPVecZ12rZta6hTcuJ6fn6+WrH3oPOf3NzcVClJPlxzfIFLnjfhVlGOqHqBNTXxA2Ou/2/WROtt1Hr77KGNbJ/t03obXczQvoqez2ITy11dXdG+fXvs2LHDcKywsFA97ty5c6mvkePG9YVEofr69erVU4GQcR2JJmWuk76O3Kalpan5WHo7d+5U7y1zp2xVdl4BbqQXrUDkvnlERETmZ9HhPBn6euGFF9Qk744dO6qVdZmZmWq1nhg5ciRq166t5hqJ8ePHo3v37pg/fz769++vVtQdOnQIK1asUM87ODhgwoQJmDNnDho1aqSCqmnTpiE0NNSQ60lW9ckKP1l5J6sBpTtw3LhxatK51NM7c+aMmvwuPVR37tzBsWPH1HF9j5a1uXLrLnQ6wMvVCbW8XC19OURERJpn0SBq6NChuHnzpkqOKZO6JUCR9AP6ieHx8fFq1Zxely5dsHbtWpXC4K233lKBkqzMa9mypaHO5MmTVSAmeZ+kx0lSGMg5JTmn3po1a1Tg1KNHD3X+wYMHq9xSxvr164e4uDjD44cfftiQRsEa6TOVh/l7qmCSiIiIzMviE8slmJFSmt27d993bMiQIaqURQKIWbNmqVIWWYknwVh5Ll++DFtiyBHFoTwiIiL72PaFTCMupSiICmeiTSIiomrBIEoj2BNFRERUvRhEaYTxnCgiIiIyPwZRGiCT3fU9UeG1vCx9OURERHaBQZQG3MzIwd28AsiivNq+Hpa+HCIiIrvAIEpDQ3mhPh5wdeZHSkREVB34G1dDK/M4qZyIiKj6MIjSAK7MIyIiqn4MorQURDFHFBERUbVhEKUB8RzOIyIiqnYMojSAw3lERETVj0GUjbubW4CkOznqPrd8ISIiqj4Momxcwq2iXqia7s7w8XCx9OUQERHZDQZRGpoP5SDZNomIiKhaMIiycb9s98KhPCIiourEIEojQRQ3HiYiIqpeDKJsHFfmERERWQaDKK0M5/l7WfpSiIiI7AqDKBtWWKhjTxQREZGFMIiyYUkZOcjNL4STowNCfN0tfTlERER2hUGUDdP3QtX29YCLEz9KIiKi6sTfvDYsIfWuuuVQHhERUfVjEGXDEm4VBVFMb0BERFT9GETZMCbaJCIishwGURroieJwHhERUfVjEGXDOCeKiIjIchhE2ajsAiAlM1fdr8vhPCIiomrHIMpGpWQX3fp6usDb3cXSl0NERGR3GETZqJQcB3XLoTwiIiLLYBBlo5Lv9UQxiCIiIrIMBlE2KiWbPVFERESWxCDKRqXkFN0yiCIiIrIMBlE2KlnfE8WVeURERBbBIMoGFRTqkMqeKCIiIotiEGWDEtOzUaBzgIuTA0J8PCx9OURERHaJQZQNir+Xqby2rwecHIuG9YiIiKh6MYiyQQm3ijYeDvNjLxQREZFdB1HLli1DREQE3N3d0alTJxw4cKDc+hs2bEDTpk1V/VatWmHLli3FntfpdJg+fTpCQkLg4eGBnj17IiYmplid1NRUjBgxAt7e3vD19cXo0aORkZFRrM6JEyfw+OOPq/cJCwvDvHnzYA24Zx4REZHlWTyIWr9+PSZOnIgZM2bgyJEjaNOmDfr06YOkpKRS6+/btw/Dhw9XQc/Ro0cxcOBAVU6dOmWoI8HO4sWLsXz5ckRFRcHLy0udMzv7XoZKQAVQp0+fRmRkJDZv3ow9e/Zg7NixhufT09PRu3dvhIeH4/Dhw3jvvffw9ttvY8WKFbCW4bwwf/ZEERER2W0QtWDBAowZMwajRo1C8+bNVeDj6emJVatWlVp/0aJF6Nu3LyZNmoRmzZph9uzZaNeuHZYuXWrohVq4cCGmTp2KAQMGoHXr1li9ejWuXbuGTZs2qTpnz57Ftm3bsHLlStXz1bVrVyxZsgTr1q1T9cSaNWuQm5urrqNFixYYNmwY/vrXv6rrtTQO5xEREVmesyXfXIIU6eWZMmWK4Zijo6Maftu/f3+pr5Hj0nNlTHqZ9AFSbGwsbty4oc6h5+Pjo4Ilea0EQ3IrQ3gdOnQw1JH68t7SczVo0CBVp1u3bnB1dS32Pu+++y5u3boFPz+/+64tJydHFePeLJGXl6eKqXuiQr1dTXpea6FvkxbbZi9t1Hr77KGNbJ/t03ob88zYvoqe06JBVHJyMgoKChAUFFTsuDyOjo4u9TUSIJVWX47rn9cfK69OYGBgseednZ3h7+9frE69evXuO4f+udKCqLlz52LmzJn3Hd++fbvqXTOF3AJAl+8EwAHnj+5H/Alolgy1ap3W26j19tlDG9k+26f1NkaaoX1ZWUUjPlYdRGmN9KgZ95JJT5RMSJe5VTKB3VT6983Dd9si0b9vL7i4uEBr5C8A+aHo1Uub7bOHNmq9ffbQRrbP9mm9jXlmbJ9+JMmqg6iAgAA4OTkhMTGx2HF5HBwcXOpr5Hh59fW3ckxW5xnXadu2raFOyYnr+fn5asWe8XlKex/j9yjJzc1NlZLkwzX1B+zqZJ7zWhOtt88e2qj19tlDG9k+26f1NrqYoX0VPZ9FJ5bLfKP27dtjx44dhmOFhYXqcefOnUt9jRw3ri8kEtXXlyE4CXKM60hEKXOd9HXkNi0tTc3H0tu5c6d6b5k7pa8jK/aMx0XlfZo0aVLqUB4RERHZF4uvzpPhr48++gifffaZWjX3yiuvIDMzU63WEyNHjiw28Xz8+PFqZd38+fPVvClJO3Do0CGMGzdOPe/g4IAJEyZgzpw5+Oabb3Dy5El1jtDQUJUKQciqPlnhJ6sCJSfVTz/9pF4vk86lnnjuuedUkCepFCQVgqRikJWBJSe1ExERkX2y+JyooUOH4ubNmyo5pkzYliE3CZL0k7jj4+PVqjm9Ll26YO3atSqFwVtvvYVGjRqplXktW7Y01Jk8ebIKxCTvk/Q4SQoDOackzdSTFAYSOPXo0UOdf/DgwSq3lPGKPpkQ/uqrr6reMhl6lGs0ziVFRERE9sviQZSQYEbfk1TS7t277zs2ZMgQVcoivVGzZs1SpSyyEk+CsfJIjqm9e/eWW4eIiIjsk8WH84iIiIhsEYMoIiIioipgEEVERERUBQyiiIiIiKqAQRQRERFRFTCIIiIiIqoCBlFEREREVcAgioiIiKgKGEQRERER2WrGcq3S6XSGDZBNSTZFzsrKUufV4s7cWm+fPbRR6+2zhzayfbZP623MM2P79L+39b/Hy8Igyozu3LmjbsPCwix9KURERFSF3+Oyl25ZHHS/FmZRlRUWFuLatWuoWbOm2s/PlBGyBGYJCQnw9vaG1mi9ffbQRq23zx7ayPbZPq23Md2M7ZPQSAKo0NBQODqWPfOJPVFmJP/j69SpY7bzy5dGiz8Y9tI+e2ij1ttnD21k+2yf1tvobab2ldcDpceJ5URERERVwCCKiIiIqAoYRNkgNzc3zJgxQ91qkdbbZw9t1Hr77KGNbJ/t03ob3aygfZxYTkRERFQF7IkiIiIiqgIGUURERERVwCCKiIiIqAoYRBERERFVAYMoG7Rs2TJERETA3d0dnTp1woEDB2Bt3n77bZWl3bg0bdrU8Hx2djZeffVV1KpVCzVq1MDgwYORmJhY7Bzx8fHo378/PD09ERgYiEmTJiE/P79Ynd27d6Ndu3ZqdUbDhg3x6aefmqU9e/bswVNPPaWy10pbNm3aVOx5WZ8xffp0hISEwMPDAz179kRMTEyxOqmpqRgxYoRKCufr64vRo0cjIyOjWJ0TJ07g8ccfV5+tZOKdN2/efdeyYcMG9f9S6rRq1Qpbtmyplja++OKL932mffv2tZk2zp07F4888ojaQUC+TwMHDsS5c+eK1anO76Wpf44r0r4nnnjivs/wT3/6k02078MPP0Tr1q0NiRU7d+6MrVu3auKzq2gbbfnzK80777yj2jBhwgTb/RxldR7ZjnXr1ulcXV11q1at0p0+fVo3ZswYna+vry4xMVFnTWbMmKFr0aKF7vr164Zy8+ZNw/N/+tOfdGFhYbodO3boDh06pHv00Ud1Xbp0MTyfn5+va9mypa5nz566o0eP6rZs2aILCAjQTZkyxVDn0qVLOk9PT93EiRN1Z86c0S1ZskTn5OSk27Ztm8nbI+//97//Xbdx40ZZzar76quvij3/zjvv6Hx8fHSbNm3SHT9+XPf73/9eV69ePd3du3cNdfr27atr06aN7ueff9bt3btX17BhQ93w4cMNz9++fVsXFBSkGzFihO7UqVO6//73vzoPDw/dv/71L0Odn376SbVx3rx5qs1Tp07Vubi46E6ePGn2Nr7wwguqDcafaWpqarE61tzGPn366D755BP1vseOHdP169dPV7duXV1GRka1fy/N8XNckfZ1795dvZfxZyifiS2075tvvtF99913uvPnz+vOnTune+utt9T3Qtpr659dRdtoy59fSQcOHNBFREToWrdurRs/frzhuK19jgyibEzHjh11r776quFxQUGBLjQ0VDd37lydtQVR8su0NGlpaeofhg0bNhiOnT17Vv3i3r9/v3osPxiOjo66GzduGOp8+OGHOm9vb11OTo56PHnyZBWoGRs6dKj6ZWJOJQOMwsJCXXBwsO69994r1kY3NzcVJAj5QZbXHTx40FBn69atOgcHB93Vq1fV4w8++EDn5+dnaJ944403dE2aNDE8fvbZZ3X9+/cvdj2dOnXSvfzyy2Ztoz6IGjBgQJmvsbU2JiUlqev94Ycfqv17WR0/xyXbp/8lbPwLqyRbap+Q79LKlSs199mV1kYtfX537tzRNWrUSBcZGVmsTbb4OXI4z4bk5ubi8OHDaqjIeH8+ebx//35YGxnOkqGh+vXrqyEe6YIV0oa8vLxi7ZChm7p16xraIbcyjBMUFGSo06dPH7Xh5OnTpw11jM+hr1Pd/y9iY2Nx48aNYtciey5J97Bxe2R4q0OHDoY6Ul8+v6ioKEOdbt26wdXVtVh7ZEjm1q1bVtFm6SKX7vMmTZrglVdeQUpKiuE5W2vj7du31a2/v3+1fi+r6+e4ZPv01qxZg4CAALRs2RJTpkxBVlaW4TlbaV9BQQHWrVuHzMxMNeSltc+utDZq6fN79dVX1XBcyeuwxc+RGxDbkOTkZPWDZfzlEfI4Ojoa1kQCCBmDll+2169fx8yZM9U8mFOnTqmAQ36Jyi/cku2Q54TcltZO/XPl1ZEfprt376q5SdVBfz2lXYvxtUrwYczZ2Vn9gjOuU69evfvOoX/Oz8+vzDbrz2FOMv/p6aefVtd48eJFvPXWW3jyySfVPzpOTk421cbCwkI1D+Oxxx5Tv4z0718d30sJFs39c1xa+8Rzzz2H8PBw9ceNzE174403VAC7ceNGm2jfyZMnVUAh82ZkvsxXX32F5s2b49ixY5r57MpqoxY+PyGB4ZEjR3Dw4EGUZIs/gwyiyCzkl6ueTJSUoEp++D///PNqC27ItIYNG2a4L38JyufaoEED1TvVo0cP2BL5S1gC+h9//BFaVFb7xo4dW+wzlIUQ8tlJUCyfpbWTP8okYJJeti+++AIvvPACfvjhB2hJWW2UQMrWP7+EhASMHz8ekZGRajK3FnA4z4ZIF678xV9ypYI8Dg4OhjWTvywaN26MCxcuqGuV7tS0tLQy2yG3pbVT/1x5dWRVS3UGavrrKe9zkdukpKRiz8tqElnNZoo2W+Lzl2Fa+U7KZ2pLbRw3bhw2b96MXbt2oU6dOobj1fW9NPfPcVntK438cSOMP0Nrbp/0UshKq/bt26vViG3atMGiRYs089mV10YtfH6HDx9W/0bIqjnppZYiAeLixYvVfekJsrXPkUGUDZEfLvnB2rFjR7Fue3lsPGZujWSZu/y1JH85SRtcXFyKtUO6pGXOlL4dcivd2sa/lOWvF/kh0HdtSx3jc+jrVPf/Cxmekh8842uRbmOZB2TcHvmHQf4R0du5c6f6/PT/EEodSTMgcwKM2yN/mcowlzW1WVy5ckXNiZLP1BbaKPPlJcCQ4RG5rpLDitX1vTTXz/Gvta800uMhjD9Da21faeS8OTk5Nv/ZVaSNWvj8evTooa5PrltfZA6lzJnV37e5z7HS0+rJomRZpqz6+vTTT9VqqLFjx6plmcYrFazBa6+9ptu9e7cuNjZWLVmX5aiyDFVWDOmXscry6507d6plrJ07d1al5DLW3r17q+XasjT1oYceKnUZ66RJk9QKjmXLlpktxYGsJpHltFLkx2bBggXqflxcnCHFgXwOX3/9te7EiRNqFVtpKQ4efvhhXVRUlO7HH39Uq1OMl//LyhRZ/v/888+rJc3yWUv7Si7/d3Z21r3//vuqzbIK0lQpDsprozz3+uuvqxUy8pl+//33unbt2qk2ZGdn20QbX3nlFZWGQr6XxkvEs7KyDHWq63tpjp/jX2vfhQsXdLNmzVLtks9Qvqv169fXdevWzSba9+abb6qVhnLt8jMmj2Xl5/bt223+s6tIG2398ytLyRWHtvY5MoiyQZLzQr5kkuNClmlKTh5rI8tJQ0JC1DXWrl1bPZZ/BPQkuPjzn/+slu/Kl33QoEHqH3xjly9f1j355JMqj5AEYBKY5eXlFauza9cuXdu2bdX7yD8okifHHOR9JLAoWWTZvz7NwbRp01SAID+YPXr0UHlejKWkpKiAokaNGmo57qhRo1RwYkxyTHXt2lWdQ/6/SXBW0ueff65r3LixarMs45W8MuZuo/wiln+05B8rCWjCw8NVXpWS/+BYcxtLa5sU4+9MdX4vTf1z/Gvti4+PV79w/f391f97yeElv2SM8wxZc/teeukl9b2T88n3UH7G9AGUrX92FWmjrX9+FQ2ibO1zdJD/VK1jjoiIiMh+cU4UERERURUwiCIiIiKqAgZRRERERFXAIIqIiIioChhEEREREVUBgygiIiKiKmAQRURERFQFDKKIiIiIqoBBFBHRPREREVi4cKGlL4OIbASDKCKyOQ4ODuWWt99+u0rnPXjwIMaOHQtzeeKJJzBhwgSznZ+IqpdzNb8fEdEDu379uuH++vXrMX36dLXbu16NGjUM92Vnq4KCAjg7//o/dw899JAZrpaItIo9UURkc4KDgw3Fx8dH9T7pH0dHR6NmzZrYunUr2rdvDzc3N/z444+4ePEiBgwYgKCgIBVkPfLII/j+++/LHc6T865cuRKDBg2Cp6cnGjVqhG+++abca/vggw9UPXd3d/VezzzzjDr+4osv4ocffsCiRYsMPWaXL19Wz506dQpPPvmkui55zfPPP4/k5ORiPVjjxo1TRdobEBCAadOmqQCRiCyHQRQRadKbb76Jd955B2fPnkXr1q2RkZGBfv36YceOHTh69Cj69u2Lp556CvHx8eWeZ+bMmXj22Wdx4sQJ9foRI0YgNTW11LqHDh3CX//6V8yaNUv1jG3btg3dunVTz0nw1LlzZ4wZM0b1pEkJCwtDWloafvvb3+Lhhx9Wr5fXJCYmqvc09tlnn6netAMHDqhzLViwQAV4RGRBOiIiG/bJJ5/ofHx8DI937dol3TO6TZs2/eprW7RooVuyZInhcXh4uO6f//yn4bGcZ+rUqYbHGRkZ6tjWrVtLPd+XX36p8/b21qWnp5f6fPfu3XXjx48vdmz27Nm63r17FzuWkJCg3ufcuXOG1zVr1kxXWFhoqPPGG2+oY0RkOeyJIiJN6tChQ7HH0hP1+uuvo1mzZvD19VVDZ9JL9Ws9UdKLpefl5QVvb28kJSWVWrdXr14IDw9H/fr11ZDcmjVrkJWVVe75jx8/jl27dqnr0ZemTZuq52QIUu/RRx9VQ4B60qsVExOj5nsRkWVwYjkRaZIEPMYkgIqMjMT777+Phg0bwsPDQ81Xys3NLfc8Li4uxR5LIFNYWFhqXZmLdeTIEezevRvbt29XE95lpaCs+pPArTQS3Mmw4rvvvnvfcyEhIRVoKRFZCoMoIrILP/30k5rcLZPE9cGLfmK3Kcm8pZ49e6oyY8YMFTzt3LkTTz/9NFxdXe/rOWrXrh2+/PJLNam9vBWEUVFRxR7//PPPagK7k5OTydtARBXD4TwisgsScGzcuBHHjh1TQ2jPPfdcmT1KVbV582YsXrxYvUdcXBxWr16t3qNJkybqeQmUJBiS4E1W38lzr776qpqoPnz4cNVjJUN4//vf/zBq1KhiAZcMO06cOFFNWP/vf/+LJUuWYPz48Sa9fiKqHAZRRGQXZDWbn58funTpoobP+vTpo3qBTEl6nSRQk9V2Mvdq+fLlKuBp0aKFYUhReo6aN2+uclJJYBQaGqp6ySRg6t27N1q1aqUScsq5HB1/+Sd65MiRuHv3Ljp27KgCLwmgzJkYlIh+nYPMLq9APSIishDJE9W2bVtuSUNkZdgTRURERFQFDKKIiIiIqoDDeURERERVwJ4oIiIioipgEEVERERUBQyiiIiIiKqAQRQRERFRFTCIIiIiIqoCBlFEREREVcAgioiIiKgKGEQRERERofL+HykBbUSWEWEkAAAAAElFTkSuQmCC"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 43
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "XHj_EjzlN4yW"
   },
   "source": [
    "### 优化器"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "1EVLKx2rN4yW",
    "ExecuteTime": {
     "end_time": "2025-02-06T03:22:41.395632Z",
     "start_time": "2025-02-06T03:22:41.392126Z"
    }
   },
   "source": [
    "from torch.optim.lr_scheduler import LambdaLR\n",
    "from torch.optim import Adam\n",
    "\n",
    "def get_optimizer(model, config):\n",
    "    base_lr = 0.1\n",
    "    beta1 = config[\"beta1\"] # Adam 的 beta1\n",
    "    beta2 = config[\"beta2\"] # Adam 的 beta2\n",
    "    eps = config[\"eps\"]\n",
    "    optimizer = Adam(model.parameters(), lr=base_lr, betas=(beta1, beta2), eps=eps)\n",
    "    lr_scheduler = NoamDecayScheduler(config) #config是一个字典，包含了学习率衰减的参数\n",
    "    # 使用 LambdaLR 调度器，它可以根据给定的函数 lr_lambda 调整学习率。这里将 lr_scheduler 作为函数传递给 LambdaLR，它包含了特定于模型或任务的学习率调度规则\n",
    "    scheduler = LambdaLR(optimizer, lr_lambda=lr_scheduler)\n",
    "    return optimizer, scheduler"
   ],
   "outputs": [],
   "execution_count": 44
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "JBhiO7O2N4yW"
   },
   "source": [
    "### Callback"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "rWFMJwBkN4yX",
    "ExecuteTime": {
     "end_time": "2025-02-06T03:22:52.323631Z",
     "start_time": "2025-02-06T03:22:46.482716Z"
    }
   },
   "source": [
    "from torch.utils.tensorboard import SummaryWriter\n",
    "\n",
    "\n",
    "class TensorBoardCallback:\n",
    "    def __init__(self, log_dir, flush_secs=10):\n",
    "        \"\"\"\n",
    "        Args:\n",
    "            log_dir (str): dir to write log.\n",
    "            flush_secs (int, optional): write to dsk each flush_secs seconds. Defaults to 10.\n",
    "        \"\"\"\n",
    "        self.writer = SummaryWriter(log_dir=log_dir, flush_secs=flush_secs)\n",
    "\n",
    "    def draw_model(self, model, input_shape):\n",
    "        self.writer.add_graph(model, input_to_model=torch.randn(input_shape))\n",
    "\n",
    "    def add_loss_scalars(self, step, loss, val_loss):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/loss\",\n",
    "            tag_scalar_dict={\"loss\": loss, \"val_loss\": val_loss},\n",
    "            global_step=step,\n",
    "            )\n",
    "\n",
    "    def add_acc_scalars(self, step, acc, val_acc):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/accuracy\",\n",
    "            tag_scalar_dict={\"accuracy\": acc, \"val_accuracy\": val_acc},\n",
    "            global_step=step,\n",
    "        )\n",
    "\n",
    "    def add_lr_scalars(self, step, learning_rate):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/learning_rate\",\n",
    "            tag_scalar_dict={\"learning_rate\": learning_rate},\n",
    "            global_step=step,\n",
    "\n",
    "        )\n",
    "\n",
    "    def __call__(self, step, **kwargs):\n",
    "        # add loss\n",
    "        loss = kwargs.pop(\"loss\", None)\n",
    "        val_loss = kwargs.pop(\"val_loss\", None)\n",
    "        if loss is not None and val_loss is not None:\n",
    "            self.add_loss_scalars(step, loss, val_loss)\n",
    "        # add acc\n",
    "        acc = kwargs.pop(\"acc\", None)\n",
    "        val_acc = kwargs.pop(\"val_acc\", None)\n",
    "        if acc is not None and val_acc is not None:\n",
    "            self.add_acc_scalars(step, acc, val_acc)\n",
    "        # add lr\n",
    "        learning_rate = kwargs.pop(\"lr\", None)\n",
    "        if learning_rate is not None:\n",
    "            self.add_lr_scalars(step, learning_rate)\n"
   ],
   "outputs": [],
   "execution_count": 45
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "64y_NBHMN4yX",
    "ExecuteTime": {
     "end_time": "2025-02-06T03:22:57.534600Z",
     "start_time": "2025-02-06T03:22:57.531589Z"
    }
   },
   "source": [
    "class SaveCheckpointsCallback:\n",
    "    def __init__(self, save_dir, save_step=5000, save_best_only=True):\n",
    "        \"\"\"\n",
    "        Save checkpoints each save_epoch epoch.\n",
    "        We save checkpoint by epoch in this implementation.\n",
    "        Usually, training scripts with pytorch evaluating model and save checkpoint by step.\n",
    "\n",
    "        Args:\n",
    "            save_dir (str): dir to save checkpoint\n",
    "            save_epoch (int, optional): the frequency to save checkpoint. Defaults to 1.\n",
    "            save_best_only (bool, optional): If True, only save the best model or save each model at every epoch.\n",
    "        \"\"\"\n",
    "        self.save_dir = save_dir\n",
    "        self.save_step = save_step\n",
    "        self.save_best_only = save_best_only\n",
    "        self.best_metrics = - np.inf\n",
    "\n",
    "        # mkdir\n",
    "        if not os.path.exists(self.save_dir):\n",
    "            os.mkdir(self.save_dir)\n",
    "\n",
    "    def __call__(self, step, state_dict, metric=None):\n",
    "        if step % self.save_step > 0:\n",
    "            return\n",
    "\n",
    "        if self.save_best_only:\n",
    "            assert metric is not None\n",
    "            if metric >= self.best_metrics:\n",
    "                # save checkpoints\n",
    "                torch.save(state_dict, os.path.join(self.save_dir, \"best.ckpt\"))\n",
    "                # update best metrics\n",
    "                self.best_metrics = metric\n",
    "        else:\n",
    "            torch.save(state_dict, os.path.join(self.save_dir, f\"{step}.ckpt\"))\n",
    "\n"
   ],
   "outputs": [],
   "execution_count": 46
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "Uk4PEb70N4yX",
    "ExecuteTime": {
     "end_time": "2025-02-06T03:23:00.622493Z",
     "start_time": "2025-02-06T03:23:00.619816Z"
    }
   },
   "source": [
    "class EarlyStopCallback:\n",
    "    def __init__(self, patience=5, min_delta=0.01):\n",
    "        \"\"\"\n",
    "\n",
    "        Args:\n",
    "            patience (int, optional): Number of epochs with no improvement after which training will be stopped.. Defaults to 5.\n",
    "            min_delta (float, optional): Minimum change in the monitored quantity to qualify as an improvement, i.e. an absolute\n",
    "                change of less than min_delta, will count as no improvement. Defaults to 0.01.\n",
    "        \"\"\"\n",
    "        self.patience = patience\n",
    "        self.min_delta = min_delta\n",
    "        self.best_metric = - np.inf\n",
    "        self.counter = 0\n",
    "\n",
    "    def __call__(self, metric):\n",
    "        if metric >= self.best_metric + self.min_delta:\n",
    "            # update best metric\n",
    "            self.best_metric = metric\n",
    "            # reset counter\n",
    "            self.counter = 0\n",
    "        else:\n",
    "            self.counter += 1\n",
    "\n",
    "    @property\n",
    "    def early_stop(self):\n",
    "        return self.counter >= self.patience\n"
   ],
   "outputs": [],
   "execution_count": 47
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "_AB84Qx1N4yX"
   },
   "source": [
    "### training & valuating"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "1mKPSFkON4yX",
    "ExecuteTime": {
     "end_time": "2025-02-06T03:23:29.989603Z",
     "start_time": "2025-02-06T03:23:29.986457Z"
    }
   },
   "source": [
    "@torch.no_grad()\n",
    "def evaluating(model, dataloader, loss_fct):\n",
    "    loss_list = []\n",
    "    for batch in dataloader:\n",
    "        encoder_inputs = batch[\"encoder_inputs\"]\n",
    "        encoder_inputs_mask = batch[\"encoder_inputs_mask\"]\n",
    "        decoder_inputs = batch[\"decoder_inputs\"]\n",
    "        decoder_labels = batch[\"decoder_labels\"]\n",
    "        decoder_labels_mask = batch[\"decoder_labels_mask\"]\n",
    "\n",
    "        # 前向计算\n",
    "        outputs = model(\n",
    "            encoder_inputs=encoder_inputs,\n",
    "            decoder_inputs=decoder_inputs,\n",
    "            encoder_inputs_mask=encoder_inputs_mask\n",
    "            )\n",
    "        logits = outputs.logits\n",
    "        loss = loss_fct(logits, decoder_labels, padding_mask=decoder_labels_mask)         # 验证集损失\n",
    "        loss_list.append(loss.cpu().item())\n",
    "\n",
    "    return np.mean(loss_list)\n"
   ],
   "outputs": [],
   "execution_count": 48
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "id": "PClBmtgWN4yY",
    "ExecuteTime": {
     "end_time": "2024-08-05T08:06:36.549252Z",
     "start_time": "2024-08-05T08:06:36.514271Z"
    }
   },
   "outputs": [],
   "source": [
    "# 训练\n",
    "def training(\n",
    "    model,\n",
    "    train_loader,\n",
    "    val_loader,\n",
    "    epoch,\n",
    "    loss_fct,\n",
    "    optimizer,\n",
    "    scheduler=None,\n",
    "    tensorboard_callback=None,\n",
    "    save_ckpt_callback=None,\n",
    "    early_stop_callback=None,\n",
    "    eval_step=500,\n",
    "    ):\n",
    "    record_dict = {\n",
    "        \"train\": [],\n",
    "        \"val\": []\n",
    "    }\n",
    "\n",
    "    global_step = 1\n",
    "    model.train()\n",
    "    with tqdm(total=epoch * len(train_loader)) as pbar:\n",
    "        for epoch_id in range(epoch):\n",
    "            # training\n",
    "            for batch in train_loader:\n",
    "                encoder_inputs = batch[\"encoder_inputs\"]\n",
    "                encoder_inputs_mask = batch[\"encoder_inputs_mask\"]\n",
    "                decoder_inputs = batch[\"decoder_inputs\"]\n",
    "                decoder_labels = batch[\"decoder_labels\"]\n",
    "                decoder_labels_mask = batch[\"decoder_labels_mask\"]\n",
    "                # 梯度清空\n",
    "                optimizer.zero_grad()\n",
    "\n",
    "                # 前向计算\n",
    "                outputs = model(\n",
    "                    encoder_inputs=encoder_inputs,\n",
    "                    decoder_inputs=decoder_inputs,\n",
    "                    encoder_inputs_mask=encoder_inputs_mask\n",
    "                    )\n",
    "                logits = outputs.logits\n",
    "                loss = loss_fct(logits, decoder_labels, padding_mask=decoder_labels_mask)\n",
    "\n",
    "                # 梯度回传\n",
    "                loss.backward()\n",
    "\n",
    "                # 调整优化器，包括学习率的变动等\n",
    "                optimizer.step()\n",
    "                if scheduler is not None:\n",
    "                    scheduler.step() # 更新学习率\n",
    "\n",
    "                loss = loss.cpu().item()\n",
    "                # record\n",
    "                record_dict[\"train\"].append({\n",
    "                    \"loss\": loss, \"step\": global_step\n",
    "                })\n",
    "\n",
    "                # evaluating\n",
    "                if global_step % eval_step == 0:\n",
    "                    model.eval()\n",
    "                    val_loss = evaluating(model, val_loader, loss_fct)\n",
    "                    record_dict[\"val\"].append({\n",
    "                        \"loss\": val_loss, \"step\": global_step\n",
    "                    })\n",
    "                    model.train()\n",
    "\n",
    "                    # 1. 使用 tensorboard 可视化\n",
    "                    cur_lr = optimizer.param_groups[0][\"lr\"] if scheduler is None else scheduler.get_last_lr()[0]\n",
    "                    if tensorboard_callback is not None:\n",
    "                        tensorboard_callback(\n",
    "                            global_step,\n",
    "                            loss=loss, val_loss=val_loss,\n",
    "                            lr=cur_lr,\n",
    "                            )\n",
    "\n",
    "                    # 2. 保存模型权重 save model checkpoint\n",
    "                    if save_ckpt_callback is not None:\n",
    "                        save_ckpt_callback(global_step, model.state_dict(), metric=-val_loss)\n",
    "\n",
    "                    # 3. 早停 Early Stop\n",
    "                    if early_stop_callback is not None:\n",
    "                        early_stop_callback(-val_loss)\n",
    "                        if early_stop_callback.early_stop:\n",
    "                            print(f\"Early stop at epoch {epoch_id} / global_step {global_step}\")\n",
    "                            return record_dict\n",
    "\n",
    "                # udate step\n",
    "                global_step += 1\n",
    "                pbar.update(1)\n",
    "            pbar.set_postfix({\"epoch\": epoch_id, \"loss\": loss, \"val_loss\": val_loss})\n",
    "\n",
    "    return record_dict\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "khZqMS8pN4yY",
    "outputId": "2367a363-585b-4321-f7ea-cb11d9623008",
    "ExecuteTime": {
     "end_time": "2024-08-05T08:06:36.628920Z",
     "start_time": "2024-08-05T08:06:36.541257800Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "load train dataset from wmt16\\.cache\\de2en_train_128.npy\n",
      "load val dataset from wmt16\\.cache\\de2en_val_128.npy\n"
     ]
    }
   ],
   "source": [
    "#模型的超参\n",
    "config = {\n",
    "    \"bos_idx\": 1,\n",
    "    \"eos_idx\": 3,\n",
    "    \"pad_idx\": 0,\n",
    "    \"vocab_size\": len(word2idx),\n",
    "    \"max_length\": 128,\n",
    "    \"d_model\": 512,\n",
    "    \"dim_feedforward\": 2048, # FFN 的隐藏层大小\n",
    "    \"dropout\": 0.1,\n",
    "    \"layer_norm_eps\": 1e-6, # 层归一化的 epsilon, 防止除零错误\n",
    "    \"num_heads\": 8,\n",
    "    \"num_decoder_layers\": 6,\n",
    "    \"num_encoder_layers\": 6,\n",
    "    \"label_smoothing\": 0.1,\n",
    "    \"beta1\": 0.9, # Adam 的 beta1\n",
    "    \"beta2\": 0.98,\n",
    "    \"eps\": 1e-9,\n",
    "    \"warmup_steps\": 4_000,\n",
    "    \"share_embedding\": False, # 是否共享词向量\n",
    "    }\n",
    "\n",
    "\n",
    "def get_dl(dataset, batch_size, shuffle=True):\n",
    "    sampler = TransformerBatchSampler(dataset, batch_size=batch_size, shuffle_batch=shuffle)\n",
    "    sample_dl = DataLoader(dataset, batch_sampler=sampler, collate_fn=partial(collate_fct, tokenizer=tokenizer))\n",
    "    return sample_dl\n",
    "\n",
    "# dataset\n",
    "train_ds = LangPairDataset(\"train\", max_length=config[\"max_length\"])\n",
    "val_ds = LangPairDataset(\"val\", max_length=config[\"max_length\"])\n",
    "# tokenizer\n",
    "tokenizer = Tokenizer(word2idx=word2idx, idx2word=idx2word, max_length=config[\"max_length\"])\n",
    "batch_size = 2048\n",
    "# dataloader\n",
    "train_dl = get_dl(train_ds, batch_size=batch_size, shuffle=True)\n",
    "val_dl = get_dl(val_ds, batch_size=batch_size, shuffle=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "模型参数量: 59038198\n"
     ]
    }
   ],
   "source": [
    "#计算模型参数量\n",
    "model = TransformerModel(config)\n",
    "print(f\"模型参数量: {sum(p.numel() for p in model.parameters() if p.requires_grad)}\")"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-08-05T08:52:53.233851300Z",
     "start_time": "2024-08-05T08:52:51.458743700Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": [
       "{'bos_idx': 1,\n",
       " 'eos_idx': 3,\n",
       " 'pad_idx': 0,\n",
       " 'vocab_size': 9718,\n",
       " 'max_length': 128,\n",
       " 'd_model': 512,\n",
       " 'dim_feedforward': 2048,\n",
       " 'dropout': 0.1,\n",
       " 'layer_norm_eps': 1e-06,\n",
       " 'num_heads': 8,\n",
       " 'num_decoder_layers': 6,\n",
       " 'num_encoder_layers': 6,\n",
       " 'label_smoothing': 0.1,\n",
       " 'beta1': 0.9,\n",
       " 'beta2': 0.98,\n",
       " 'eps': 1e-09,\n",
       " 'warmup_steps': 4000,\n",
       " 'share_embedding': False}"
      ]
     },
     "metadata": {},
     "execution_count": 51
    }
   ],
   "source": [
    "config"
   ],
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-07T08:52:38.372364400Z",
     "start_time": "2024-05-07T08:52:38.191467100Z"
    },
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "63slV04gWLn8",
    "outputId": "5c5ede03-0f6f-48d5-a177-d961886ec340"
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 49,
     "referenced_widgets": [
      "55146ac7395840dca847e0f63aa80561",
      "abb9bc76c0ce4634bd340be20c074b8c",
      "a89d790df59245fcaf26335d4903c9b4",
      "f837255914194dc792cf1514dee03dc5",
      "46a51a1719d8444eb5877720253d3c37",
      "013d2a6b90144432bbfb15136235faba",
      "2b82e42c34804b13bc83be4c7009d4e2",
      "9233439bdd6746c28ad4a20ef47799f6",
      "0e10428326bc436e8dbc079e89570bde",
      "0fe4ed7283c04496affe727c235d31c4",
      "0c0c7229347b49ffbb9a0f7bd41199b9"
     ]
    },
    "id": "tVO2zJ04N4yY",
    "outputId": "7d4079f5-65d4-4da1-9001-91aa5525250e"
   },
   "outputs": [
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "  0%|          | 0/280 [00:00<?, ?it/s]"
      ],
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "55146ac7395840dca847e0f63aa80561"
      }
     },
     "metadata": {}
    }
   ],
   "source": [
    "epoch = 20\n",
    "\n",
    "# model\n",
    "model = TransformerModel(config)\n",
    "# 1. 定义损失函数 采用交叉熵损失\n",
    "loss_fct = CrossEntropyWithPadding(config)\n",
    "# 2. 定义优化器 采用 adam\n",
    "# Optimizers specified in the torch.optim package\n",
    "optimizer, scheduler = get_optimizer(model, config)\n",
    "\n",
    "# 1. tensorboard 可视化\n",
    "if not os.path.exists(\"runs\"):\n",
    "    os.mkdir(\"runs\")\n",
    "exp_name = \"translate-transformer-{}\".format(\"share\" if config[\"share_embedding\"] else \"not-share\")\n",
    "tensorboard_callback = TensorBoardCallback(f\"runs/{exp_name}\")\n",
    "# tensorboard_callback.draw_model(model, [1, MAX_LENGTH])\n",
    "# 2. save best\n",
    "if not os.path.exists(\"checkpoints\"):\n",
    "    os.makedirs(\"checkpoints\")\n",
    "save_ckpt_callback = SaveCheckpointsCallback(\n",
    "    f\"checkpoints/{exp_name}\", save_step=500, save_best_only=True)\n",
    "# 3. early stop\n",
    "early_stop_callback = EarlyStopCallback(patience=8)\n",
    "\n",
    "model = model.to(device)\n",
    "\n",
    "record = training(\n",
    "    model,\n",
    "    train_dl,\n",
    "    val_dl,\n",
    "    epoch,\n",
    "    loss_fct,\n",
    "    optimizer,\n",
    "    scheduler,\n",
    "    tensorboard_callback=tensorboard_callback,\n",
    "    save_ckpt_callback=save_ckpt_callback,\n",
    "    early_stop_callback=None,\n",
    "    eval_step=500\n",
    "    )\n",
    "\n",
    "# Training took 3.5 days on 8 P100 GPUs\n",
    "# We trained the base models for a total of 100,000 steps or 12 hours. For our big models,(described on the bottom line of table 3), step time was 1.0 seconds. The big models were trained for 300,000 steps (3.5 days)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "rTjbeFlIN4yZ"
   },
   "source": [
    "## 推理\n",
    "\n",
    "- 翻译项目的评估指标一般是BLEU4，感兴趣的同学自行了解并实现\n",
    "- 接下来进行翻译推理，并作出注意力的热度图"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "WxsjkyQgN4yZ",
    "outputId": "5ce160c2-ce7e-4bc3-d2b6-a332c7fcf6a1"
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Collecting fastBPE\n",
      "  Downloading fastBPE-0.1.0.tar.gz (35 kB)\n",
      "  Preparing metadata (setup.py) ... \u001B[?25l\u001B[?25hdone\n",
      "Building wheels for collected packages: fastBPE\n",
      "  Building wheel for fastBPE (setup.py) ... \u001B[?25l\u001B[?25hdone\n",
      "  Created wheel for fastBPE: filename=fastBPE-0.1.0-cp310-cp310-linux_x86_64.whl size=806588 sha256=b77d4a1091f1aa812ca7c62cb09e4397a6cb8ae13061a3c1aeb5bc104e3d8dc7\n",
      "  Stored in directory: /root/.cache/pip/wheels/13/5d/b9/4b8897941ebc9e8c6cc3f3ffd3ea5115731754269205098754\n",
      "Successfully built fastBPE\n",
      "Installing collected packages: fastBPE\n",
      "Successfully installed fastBPE-0.1.0\n"
     ]
    }
   ],
   "source": [
    "# !pip install Cython  # if failed to install fastBPE, try this line\n",
    "!pip install fastBPE #分词使用\n",
    "# 在 Windows 系统上并没有 sys/mman.h 文件"
   ]
  },
  {
   "cell_type": "code",
   "source": [
    "exp_name"
   ],
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 35
    },
    "id": "f6Ry1PcAn4k1",
    "outputId": "6393524e-e5c3-4f93-dd9d-f249ca52bc05"
   },
   "execution_count": null,
   "outputs": [
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": [
       "'translate-transformer-not-share'"
      ],
      "application/vnd.google.colaboratory.intrinsic+json": {
       "type": "string"
      }
     },
     "metadata": {},
     "execution_count": 54
    }
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {
    "id": "jT1Mqiq3N4yZ",
    "ExecuteTime": {
     "end_time": "2024-08-05T03:10:32.326542400Z",
     "start_time": "2024-08-05T03:10:31.006376300Z"
    }
   },
   "outputs": [],
   "source": [
    "import torch\n",
    "\n",
    "state_dict = torch.load(f\"best.ckpt\", map_location=\"cpu\")\n",
    "\n",
    "# state_dict1 = torch.load(\"epoch125-step132426.ckpt\", map_location=\"cpu\")\n",
    "# state_dict = state_dict1[\"state_dict\"]\n",
    "\n",
    "# update keys by dropping `model`\n",
    "# for key in list(state_dict):\n",
    "#     state_dict[key.replace(\"model.\", \"\")] = state_dict.pop(key)\n"
   ]
  },
  {
   "cell_type": "code",
   "source": [
    "!pip install nltk"
   ],
   "metadata": {
    "id": "eKwIDdjgvTlO",
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "outputId": "35979ff2-a16d-4aa4-881a-8496e39e2469",
    "ExecuteTime": {
     "end_time": "2024-08-05T03:10:46.720508800Z",
     "start_time": "2024-08-05T03:10:36.179313900Z"
    }
   },
   "execution_count": 52,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Defaulting to user installation because normal site-packages is not writeable\n",
      "Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple\n",
      "Collecting nltk\n",
      "  Using cached https://pypi.tuna.tsinghua.edu.cn/packages/a6/0a/0d20d2c0f16be91b9fa32a77b76c60f9baf6eba419e5ef5deca17af9c582/nltk-3.8.1-py3-none-any.whl (1.5 MB)\n",
      "Requirement already satisfied: click in c:\\users\\administrator\\appdata\\roaming\\python\\python312\\site-packages (from nltk) (8.1.7)\n",
      "Requirement already satisfied: joblib in c:\\users\\administrator\\appdata\\roaming\\python\\python312\\site-packages (from nltk) (1.4.2)\n",
      "Requirement already satisfied: regex>=2021.8.3 in c:\\users\\administrator\\appdata\\roaming\\python\\python312\\site-packages (from nltk) (2024.7.24)\n",
      "Requirement already satisfied: tqdm in c:\\users\\administrator\\appdata\\roaming\\python\\python312\\site-packages (from nltk) (4.66.4)\n",
      "Requirement already satisfied: colorama in c:\\users\\administrator\\appdata\\roaming\\python\\python312\\site-packages (from click->nltk) (0.4.6)\n",
      "Installing collected packages: nltk\n",
      "Successfully installed nltk-3.8.1\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "[notice] A new release of pip is available: 24.1.2 -> 24.2\n",
      "[notice] To update, run: python.exe -m pip install --upgrade pip\n"
     ]
    }
   ]
  },
  {
   "cell_type": "code",
   "source": [
    "!rm -r wmt16/.cache"
   ],
   "metadata": {
    "id": "WVksjIhL_pt9"
   },
   "execution_count": 55,
   "outputs": []
  },
  {
   "cell_type": "code",
   "source": [
    "tokenizer.decode([[   5,   16,    6,   23,  150,   80, 8248,   35,  232,    4,    3]])"
   ],
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "2MY69-6WWSjp",
    "outputId": "911d9066-7917-4917-b5cc-d679a1c63865"
   },
   "execution_count": 38,
   "outputs": [
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": [
       "['a man in an orange hat starring at something .']"
      ]
     },
     "metadata": {},
     "execution_count": 38
    }
   ]
  },
  {
   "cell_type": "code",
   "source": [
    "from nltk.translate.bleu_score import sentence_bleu\n",
    "# load checkpoints\n",
    "model = TransformerModel(config)\n",
    "model.load_state_dict(state_dict)\n",
    "\n",
    "loss_fct = CrossEntropyWithPadding(config)\n",
    "# from dataset import LangPairDataset\n",
    "test_ds = LangPairDataset(\"test\", max_length=128, data_dir=\"./wmt16\")\n",
    "test_dl = DataLoader(test_ds, batch_size=1, collate_fn=partial(collate_fct, tokenizer=tokenizer))\n",
    "\n",
    "model = model.to(device)\n",
    "model.eval()\n",
    "collect = {}\n",
    "loss_collect = []\n",
    "\n",
    "predictions = []\n",
    "answers = []\n",
    "# 初始化BLEU分数列表\n",
    "bleu_scores = []\n",
    "for idx, batch in tqdm(enumerate(test_dl)):\n",
    "    encoder_inputs = batch[\"encoder_inputs\"]\n",
    "    encoder_inputs_mask = batch[\"encoder_inputs_mask\"]\n",
    "    decoder_inputs = batch[\"decoder_inputs\"]\n",
    "    decoder_labels = batch[\"decoder_labels\"]\n",
    "    # print(decoder_labels.cpu())\n",
    "    # decoder_labels1=tokenizer.decode(decoder_labels.cpu().numpy())\n",
    "    # print(decoder_labels1)\n",
    "    # 前向计算\n",
    "    outputs = model(\n",
    "        encoder_inputs=encoder_inputs,\n",
    "        decoder_inputs=decoder_inputs,\n",
    "        encoder_inputs_mask=encoder_inputs_mask\n",
    "        )\n",
    "    loss = loss_fct(outputs.logits, decoder_labels)         # 验证集损失\n",
    "\n",
    "    # print(outputs.logits.shape, decoder_labels.shape)\n",
    "\n",
    "    # loss = loss_fct(outputs.logits[:, :decoder_labels.shape[1]], decoder_labels)         # 验证集损失\n",
    "    # outputs = model.infer(encoder_inputs=encoder_inputs)\n",
    "    # print(outputs.logits.shape)\n",
    "    preds = outputs.logits.argmax(dim=-1) # 预测结果，[1,seq_len]\n",
    "    # print(preds.shape)\n",
    "    #把preds转为英文单词\n",
    "    preds = tokenizer.decode(preds.cpu().numpy()) #['预测句子']\n",
    "    # predictions.append(preds)\n",
    "    # print(preds)\n",
    "    #把decoder_labels转为英文单词\n",
    "    decoder_labels = tokenizer.decode(decoder_labels.cpu().numpy()) #['标签句子']\n",
    "    # answers.append(decoder_labels)\n",
    "    # print(decoder_labels)\n",
    "    belu=sentence_bleu([decoder_labels[0].split()],preds[0].split(),weights=(1, 0, 0, 0))\n",
    "    bleu_scores.append(belu)\n",
    "    collect[idx] = {\"loss\": loss.item(), \"src_inputs\": encoder_inputs, \"trg_inputs\": decoder_inputs, \"mask\": encoder_inputs_mask, \"trg_labels\": decoder_labels, \"preds\": preds}\n",
    "    loss_collect.append(loss.item())\n",
    "    # break\n",
    "\n",
    "# sort collect by value\n",
    "collect = sorted(collect.items(), key=lambda x: x[1][\"loss\"])\n",
    "print(f\"testing loss: {np.array(loss_collect).mean()}\")\n",
    "sum(bleu_scores) / len(bleu_scores)"
   ],
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 101,
     "referenced_widgets": [
      "c9db4cd83b7b4f53a0fa93b8c365debd",
      "a972aba7913b48c6973ae27bff5b9d1d",
      "22aa774ab39e4fd78b0ff08d430d2b5d",
      "9a01f02fb99b4b81ac487d23bc5daf4a",
      "19f846338f6b48c9930b58575641e5b8",
      "7d293204dc1b4d97bb5ee670787c7b7d",
      "ea8fa440f320435aa75c9bef75bc3f08",
      "4e64bcb87e584beda0408a0aa5a659ae",
      "b077d7562d814df5b6d839464dd4122f",
      "5a28babf4e2e4393bdc1a093034885ab",
      "be07d518c21149d196c610fd57b1eaec"
     ]
    },
    "id": "5QgodlOJfgKj",
    "outputId": "2907bad2-7cb1-4295-c8b0-77ac0dabf398"
   },
   "execution_count": 46,
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "load test dataset from wmt16/.cache/de2en_test_128.npy\n"
     ]
    },
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "0it [00:00, ?it/s]"
      ],
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "c9db4cd83b7b4f53a0fa93b8c365debd"
      }
     },
     "metadata": {}
    },
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "testing loss: 3.258438676626829\n"
     ]
    },
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": [
       "0.5708733100076216"
      ]
     },
     "metadata": {},
     "execution_count": 46
    }
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 535,
     "referenced_widgets": [
      "40f7e3754ad44b33acfe0a80b3648a3a",
      "b1e51beac50f4947a9dd235d8aa87603",
      "8cd9e9702e114ebc856f56975544ede8",
      "b7c7a718a8654956947108969557ca83",
      "20a27d1ec76f4d85b1ffe99401fbb5b7",
      "e0ddf3970b3e4248bc87d4649fa9c448",
      "d7bdde54e2534c49a207540bd258d3ae",
      "22484000400842f0b6e245dc610acbba",
      "a66a5b4ff37d4dafa4ba3081aa1359f4",
      "0b7866c29e5f4afe9b92de15f1b88c3e",
      "333e84a304184c57af1821620ae80f6a"
     ]
    },
    "id": "KGSym4CbN4ya",
    "outputId": "f5e9c4c2-c92e-44e6-c83a-5cb720305428",
    "ExecuteTime": {
     "end_time": "2024-05-06T13:16:14.099749Z",
     "start_time": "2024-05-06T13:16:13.991811900Z"
    }
   },
   "outputs": [
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "  0%|          | 0/128 [00:00<?, ?it/s]"
      ],
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "40f7e3754ad44b33acfe0a80b3648a3a"
      }
     },
     "metadata": {}
    },
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "<Figure size 1000x500 with 2 Axes>"
      ],
      "image/png": "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f/NLrh0+/PBDPfvss3ryySfPuaxNmzb1extyc3N15MiRiz6EESVXSVifSqOCggIdP378os57vBQUPGfo2bOnqlSp4j2eet++fWrYsKGqVKmiOnXq6Ouvv9bUqVPVq1cvm1sa2DZt2qQbbrhBLVq00IIFC3TbbbcV2S1fp04du5sIlChXXHHFRR9L/v333/u5NbgYdvYntWrVOu9jLpdLO3bs8HmmXYKCzr7CxqkTo518knlhYaEGDx6s+fPn64orrtCECROKdRglzq20rk9W+c9//qOsrCz17t3be98LL7ygMWPGqKCgQNdff70++OADxcTE+DSXQ9rOsGrVKk2bNs17+5133lFsbKzWr1+vkJAQvfzyy/rHP/5BwXOZ7Not/8ADDygtLU0RERFF7j969Kj69++vt956y2/ZpUVmZqYSExPP+nJujNHu3btVvXp1m1oW2Lp27Wp3E3hvi8nO/mTnzp0+n2dJZdey7t27V0OGDNH8+fO1b9++s0ae8tUX40OHDumJJ57Q3LlzNW3aNHXo0EGSNGDAAH366afq27ev5syZo/79+2vmzJk+ySzNStNnxw4TJkzQX//6V+/tFStWaNSoUXruuefUqFEjPf300xozZowmTJjg01z28JyhbNmy+t///uc9BKFTp05q0qSJXnzxRUlSRkaG2rZtq6ysLDubGfDO98Xp1GP++uIUHBysPXv2nHXYwf79+xUfH6+CggK/5JYm53uNs7KyVKlSJX4dC2C8t8VDf+JsHTt2VGZmph5//HElJCSc1Z916dLFJzl33323srKydM011yg9PV3vvfeePvnkE915551atmyZWrdurR9++EHXX3+9fv/9d59knguff/hCpUqVNHfuXO+Q7oMHD1Z6err3wrmzZ8/WgAEDtHXrVp/msofnDJGRkTp06JC3g1qzZo369Onjfdzlcvn12juFhYWaNm2a9xejMy8Wt2DBAr9lW6lWrVrn3XDWqlXL5xvOnJwcGWNkjNHhw4dVpkwZ72OFhYWaPXs2x177yPkuHnvkyJEirzsCD+9t8djZn5SWvuSUd999V//85z+1c+dOrVy5UjVq1NCkSZNUq1YtnxUeZ1q2bJmWLl2q5s2b+2X+p8yZM0crVqxQrVq1dOWVVyomJkY5OTkaOXKkWrduLUkKDw/XsWPH/NqO8/0+npeXp7CwML9mW82O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/KzPw4EDB/ySW7t2bb355pvq0KFDkVG13nnnHY0bN07p6ek+z7z22mvVo0cP9e/fXxEREdq4caNq1aql/v37a+vWrZozZ47PM0+x4/O/YcOGIrfz8/O1bt06TZgwQS+88MIfXtPvUti1PknSu+++6z0nbOXKlapRo4YmTpyo2rVrq0uXLn7LtdqJEyfOeUHmO++8U4MGDfLLBbQpeC7SiRMndOLECb9f6dbj8cjj8XhHXfnggw+0fPly1atXT4888ojfrspthZiYmCJf9I8ePWr5BuXxxx/XtGnTdMstt5yz8Jg4caJfcsuVK6f//ve/atiwoV/mX5J06tRJxhi99957io2NlSRlZWXpnnvuUVBQkL766iubWxj4nn/+eY0aNUoNGjRQ5cqVzxq0wF+FO++tb1jRnzi5LznTqRP4z+e+++7zS25qaqr+/e9/66233tKNN96o2bNn66efftKgQYM0cuRI9e/f3+eZy5YtU8eOHXXPPfd4By9JT0/XihUrtHjxYrVs2dLnmaeUpM//V199pZdeekmLFi3y+bztWp/eeOMNjRo1SgMHDtTzzz+vH3/8UbVr19a0adM0ffp0LVy40C+5pQUFzzm8/fbb+v7773XllVfq7rvv1vDhwzV+/HgVFBTo+uuv18yZMxUXF+e3/OPHj2vjxo1n7YFwuVx+vaigv/3RRuR0/tqgVKhQQe+8847lI5786U9/0sSJE/0yak9JU65cOa1atUrJyclF7t+wYYOuuuoqHTlyxKaWOUdMTIwmTpyo3r17W5rLe1t8dvYnTu1LSgpjjMaOHavU1FTvsOxut1tDhgzRmDFj/Ja7Y8cOpaamasOGDTpy5IhatGihp5566qzPpa+VpM//tm3b1KxZMx09etSyTH9LSkrS2LFjvRcgPbXHcNOmTUpJSdH+/fvtbqJPrFmzRi1btjzvYZB5eXn6/PPPdfvtt/s22OdnBQW4559/3pQtW9Z06NDBxMbGmkceecTEx8ebcePGmRdffNFUq1bNPPLII37L//rrr02FChWMy+U6awoKCvJbrtV69eplpk6davmJ1wkJCWbLli2WZhpjzPz5803btm3NwoULzf79+012dnaRyUliYmLM8uXLz7p/2bJlJiYmxoYWOU/lypVNRkaG5bm8t8VjZ3/i9L7k9O3mmdtTq7eveXl55scffzSrV682hw8f9mtWr169zFtvvWXLoCV2fP7PfC8PHTpkNm/ebO644w7TrFkzn+acL9Oq9alMmTLegUZOH5AiIyPDlClTxm+5VgsKCioy6lxERIR3WY0x5rfffvPLNopBC84wbdo0TZ06VT179tTatWvVpk0bzZo1y3ul7CZNmuiRRx7xW37//v11++23a9SoURccp9zXtm7dqoULF57zvJZRo0b5PM/tdmvcuHHq27evqlSpovbt2yslJUXt27f36QXMzvTEE08oLS1Nr732mqXXaujQoYMk6frrry+Saxw4aEHnzp310EMPaerUqd6LLq5evVqPPPKIbrvtNr9mW70e22XAgAF69dVX//C6Ur5m53sbiOzsT+zqSyRrPocxMTHas2ePKlWqpOjo6HNuz63avoaFhSkpKcmvGadnpaam6sEHH7S075Ts+fyf6701xigxMVEzZ870WU5JWJ9q1aql9evXq0aNGkXunzNnjho1auSXTDuYMw4sO/P2+e67XBzSdga3261t27Z5LxTndru1ceNG7wl6v/zyi2rVqnXWVat9JTIyUuvWrbP05N/Jkyfr0UcfVYUKFRQfH3/W+QD+vCL3L7/8oiVLlmjx4sVavHixMjIylJCQoJ9//tlnGWee1LhgwQLFxsaqcePGZx3H/sknn/gs93SLFy++4ON2XrHb1w4dOqT77rtP//nPf7yvb35+vrp06aJp06YpKirKL7l2rsdW69atmxYsWKC4uDhL12O73ttAZWd/YkdfIln3OVy8eLF3MBgrt6/FOUneX59DyZq+80x2fP7PfG+DgoJUsWJF1a1b13t+mq9y7FifTjdlyhQ9++yzGj9+vPr06aMpU6Zo+/btSk1N1ZQpU3TnnXf6JddqQUFB+u2337yjDZ5++J508sL0VapU8XlhyR6eM+Tn5xcZHSIsLKzIl4mQkBC//lr017/+VYsWLbK0k3r++ef1wgsv6KmnnrIs85SYmBjFxcUpJiZG0dHRCgkJUcWKFX2aceZGuFu3bj6d/8Vo3769Dh06pKlTp3qH80xKSlKfPn38/iUxPT1dmZmZZ32p8ucvcp9//rm2bdvmHaUoKSlJdevW9UveKXaux3a8xv4Ynehicu14bwOVnf2JHX2JZN3n8PQvne3bt9fSpUv1r3/9S9u3b9dHH32kqlWr6t1331WtWrV8mnux22t/H0FgRd95Jjs+/6fe59O3sQcPHvSO7OWrbaxd69PpHnzwQZUtW1YjRoxQbm6u7rrrLlWtWlVpaWmOKXbsRMFzDunp6frtt98kndyt9r///c97Mp6/Txp77bXX1KNHDy1duvScw83+7W9/83nmwYMH1aNHD5/P90KGDx+uRYsWad26dWrUqJHat2+voUOH6tprr1VMTIxPs95++23v/48dOyaPx6Ny5cpJknbt2qXPPvtMjRo10s033+zT3NOtXbtWf/7zn1WmTBnvoQATJ07U2LFjNW/ePLVo0cLnmTt27FC3bt30ww8/yOVyeXcRn+qI/Vm4T506VRMnTtTWrVslSfXq1dPAgQP14IMP+i3TjvXYrtf49ddft2U9lux5bwOZXf2JHX2JZM/n8OOPP1avXr109913a926dcrLy5MkZWdna+zYsZo9e7bPsk7vT2bMmKGePXue83lPPvmkzzJPZ2XfeS5Wf/537Nih7t27a+PGjZZtY61cn0537NgxdevWTXfffbdyc3O1adMmLV++XNWqVfNLnp1s2S76/KygAHfqhM7znejp7xM+p0yZYkJCQkz58uVNjRo1TM2aNb1TrVq1/JL5wAMPmDfeeMMv8z4fl8tlKlWqZFJTUy0dRODGG2/0LuvBgwdN5cqVTbVq1UyZMmXM66+/7rfcq6++2vTu3dvk5+d778vPzzf33Xefueaaa/yS2blzZ9OlSxfz+++/m/Lly5v09HSzdOlS07p1a7NkyRK/ZBpjzMiRI025cuXM0KFDzeeff24+//xzM3ToUFO+fHm/XD35FDvWY7teY7vWY7ve20BlZ39iR19ijD2fw+bNm5vp06cbY4qe7P3999+bypUr+y03KirKzJ49+6z7Bw0aZOLj4/2SaVffaYw9n/8zt7E//vij37exdq1Pdm3XrWbXdpGC5wy7du26qMlfKleubF544QVTWFjot4wzjR071lSoUMHcd9995uWXXzZpaWlFJn9Yv369SUtLM926dTMVKlQwVapUMT179jT/+te//LoRj4uLM5s2bTLGGDN58mTTtGlTU1hYaGbNmmUaNmzot9wyZcqYzZs3n3X/jz/+aMqWLeuXzLi4OLNhwwZjjDGRkZHmf//7nzHm5IhxzZs390umMcZUqFDBvP/++2fd//7775u4uDi/5dqxHtv1Gtu1Htv13gYqO/sTO/oSY+z5HJYtW9bs3LnTGFP0C+r27duN2+32S6Yxxnz55ZcmKirKLF261Hvf448/bhISEs65vfcFu/pOY+z5/NuxjbVrfbJru241u7aLFDyn2bBhQ7E6h02bNhX5xd4XYmJiLB9u8vRf/s6c/PlL4OnWr19v7rvvPhMSEuLXPWhly5Y1P/30kzHGmB49ephnn33WGGNMZmam3woPY4ypVKmSmTt37ln3z5kzx1SqVMkvmdHR0WbHjh3GGGNq165tFixYYIwxZtu2bX5d1qioqHMOmbxlyxYTFRXlt1w71mO7XmO71mO73ttAZHd/YkdfYow9n8NatWqZb775xhhT9Avq9OnTTaNGjfySecp7771nYmJizNq1a82jjz5qqlSpYumeF6v6TmPs+fzbsY21a32ya7tuJTu3ixQ8pwkKCjL79u276OefOXa4LwwcONC88MILPp1nSeTxeMx///tfM378eHPrrbeamJgYExwcbK644gozcOBAv+UmJyebtLQ0k5mZaSIjI82KFSuMMcasXbvWr7uq+/fvb6pVq2ZmzpxpMjMzTWZmppkxY4apVq2aGTBggF8yr776avPpp58aY4zp2bOn+fOf/2yWLVtm7r33XtO4cWO/ZBpz8hfOQYMGnXX/E088YR577DG/5drBrtfYrvW4NL23l8vu/qS09CXGnNyrlJSUZFatWmUiIiLM0qVLzb///W9TsWJF88orr/g9/x//+Idxu92mWrVqZuvWrX7NsqvvNMaez78d21i71ie7tutWsnO7yKAFpzHGaOTIkQoPD7+o5/tjKNHCwkK9+OKLmjt3rpo2bXrWiaYTJkzwSc7gwYM1ZswYlStXToMHDz7v81wul8aPH++TzNPFxsbqyJEjatasmdq3b6++ffvqmmuuUXR0tM+zTjdq1CjdddddGjRokG644Qa1bdtWkjRv3jxdccUVfst9+eWX5XK5dO+996qgoECSFBoaqkcffVTjxo3zS+aIESO8V6F+7rnn1LlzZ11zzTWKi4vTBx984NOs09chl8ulKVOmaN68ebryyislnbxWQ2Zmpu69916f59q5Hlv5Gp/OyvXYrvf2YnTo0EE7duzQjh07LM/+I3b3J1b1JZL9n8OhQ4fK4/HohhtuUG5urq699lq53W4NGTJE/fv392nW+ZavYsWKatGihV5//XXvfb58jU+xuu+0+/NvxzbWyvXpdHZ9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\n"
     },
     "metadata": {}
    },
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": [
       "['man in white shirt on a boat in a small boat.']"
      ]
     },
     "metadata": {},
     "execution_count": 41
    }
   ],
   "source": [
    "import re\n",
    "from fastBPE import fastBPE\n",
    "from sacremoses import MosesDetokenizer, MosesTokenizer\n",
    "\n",
    "# `MosesTokenizer` 和 `MosesDetokenizer` 是来自 `sacremoses` 库的工具，用于自然语言处理中的分词（Tokenization）和去标记化（Detokenization）。这些工具主要用于对文本进行预处理和后处理，通常在处理自然语言处理任务时会用到。\n",
    "#\n",
    "# ### MosesTokenizer：\n",
    "# - **作用**：将原始文本分割成单词和标点符号。\n",
    "# - **特点**：基于 Moses 翻译工具中使用的分词方法。\n",
    "# - **功能**：\n",
    "#   - 将句子分割成单词和标点符号。\n",
    "#   - 处理缩写、连字符、标点等特殊情况。\n",
    "#   - 对文本进行标记化，方便后续处理。\n",
    "#\n",
    "# ### MosesDetokenizer：\n",
    "# - **作用**：将分词后的文本重新组合成原始的句子。\n",
    "# - **特点**：用于对分词后的文本进行还原，使其恢复为可读的句子形式。\n",
    "# - **功能**：\n",
    "#   - 将分词后的单词和标点符号重新组合成句子。\n",
    "#   - 处理分词后的标点、缩写等情况，使得结果更加自然和可读。\n",
    "#\n",
    "# 这些工具通常在文本预处理和后处理过程中使用，对输入的文本进行标记化和去标记化，是一种常用的处理方式。在自然语言处理任务中，对文本进行正确的分词和还原是很重要的，而 `MosesTokenizer` 和 `MosesDetokenizer` 提供了方便、高效的工具来处理这些任务。\n",
    "\n",
    "class Translator:\n",
    "    def __init__(self, model, src_tokenizer, trg_tokenizer):\n",
    "        self.bpe = fastBPE(\"./wmt16/bpe.10000\", \"./wmt16/vocab\")\n",
    "        self.mose_tokenizer = MosesTokenizer(lang=\"de\")\n",
    "        self.mose_detokenizer = MosesDetokenizer(lang=\"en\")\n",
    "        self.model = model\n",
    "        self.model.eval()\n",
    "        self.src_tokenizer = src_tokenizer\n",
    "        self.trg_tokenizer = trg_tokenizer\n",
    "        self.pattern = re.compile(r'(@@ )|(@@ ?$)')\n",
    "\n",
    "    def draw_attention_map(self, attn_scores, cross_attn_scores, src_words_list, trg_words_list):\n",
    "        \"\"\"绘制注意力热力图\n",
    "        attn_scores (numpy.ndarray): 表示自注意力机制（self-attention）分数。\n",
    "        cross_attn_scores (numpy.ndarray): 表示交叉注意力机制的注意力分数。\n",
    "        src_words_list (list): 源语言句子的单词列表。\n",
    "        trg_words_list (list): 目标语言句子的单词列表。\n",
    "        \"\"\"\n",
    "        assert len(attn_scores.shape) == 3, \"attn_scores shape should be \" \\\n",
    "            f\"[num heads, target sequence length, target sequence length], but got {attn_scores.shape}\"\n",
    "        attn_scores = attn_scores[:, :len(trg_words_list), :len(trg_words_list)]\n",
    "\n",
    "        assert len(cross_attn_scores.shape) == 3, \"attn_scores shape should be \" \\\n",
    "            f\"[num heads, target sequence length, source sequence length], but got {cross_attn_scores.shape}\"\n",
    "        cross_attn_scores = cross_attn_scores[:, :len(trg_words_list), :len(src_words_list)]\n",
    "\n",
    "        num_heads, trg_len, src_len = cross_attn_scores.shape\n",
    "\n",
    "        fig = plt.figure(figsize=(10, 5), constrained_layout=True) # constrained_layout=True 自动调整子图参数，使之填充整个图像区域\n",
    "        grid = plt.GridSpec(trg_len, trg_len + src_len, wspace=0.1, hspace=0.1)# wspace,hspace 控制子图之间的间距\n",
    "        #下面是attn_scores的热力图\n",
    "        self_map = fig.add_subplot(grid[:,:trg_len]) #  添加子图\n",
    "        self_map.matshow(attn_scores.mean(dim=0), cmap='viridis') # 绘制热力图，cmap表示颜色,dim=0表示对第0维求均值\n",
    "        self_map.set_yticks(range(trg_len), trg_words_list, fontsize=10)\n",
    "        self_map.set_xticks(range(trg_len), [\"[BOS]\"] + trg_words_list[:-1], rotation=90)\n",
    "        #下面是cross_attn_scores的热力图\n",
    "        cross_map = fig.add_subplot(grid[:, trg_len:])\n",
    "        cross_map.matshow(cross_attn_scores.mean(dim=0), cmap='viridis')\n",
    "        cross_map.set_yticks(range(trg_len), [], fontsize=6)\n",
    "        cross_map.set_xticks(range(src_len), src_words_list, rotation=90)\n",
    "\n",
    "        plt.show()\n",
    "\n",
    "    def draw_attention_maps(self, attn_scores, cross_attn_scores, src_words_list, trg_words_list, heads_list):\n",
    "        \"\"\"绘制注意力热力图\n",
    "\n",
    "        Args:\n",
    "            - scores (numpy.ndarray): shape = [source sequence length, target sequence length]\n",
    "        \"\"\"\n",
    "        assert len(attn_scores.shape) == 3, \"attn_scores shape should be \" \\\n",
    "            f\"[num heads, target sequence length, target sequence length], but got {attn_scores.shape}\"\n",
    "        attn_scores = attn_scores[:, :len(trg_words_list), :len(trg_words_list)]\n",
    "\n",
    "        assert len(cross_attn_scores.shape) == 3, \"attn_scores shape should be \" \\\n",
    "            f\"[num heads, target sequence length, source sequence length], but got {cross_attn_scores.shape}\"\n",
    "        cross_attn_scores = cross_attn_scores[:, :len(trg_words_list), :len(src_words_list)]\n",
    "        # cross_attn_scores = cross_attn_scores[:, :len(src_words_list), :len(src_words_list)]\n",
    "\n",
    "        num_heads, trg_len, src_len = cross_attn_scores.shape\n",
    "        fig, axes = plt.subplots(2, len(heads_list), figsize=(5 * len(heads_list), 10))\n",
    "        for i, heads_idx in enumerate(heads_list):\n",
    "            axes[0, i].matshow(attn_scores[heads_idx], cmap='viridis')\n",
    "            axes[0, i].set_yticks(range(trg_len), trg_words_list)\n",
    "            axes[0, i].set_xticks(range(trg_len), [\"[BOS]\"] + trg_words_list[:-1], rotation=90)\n",
    "            axes[0, i].set_title(f\"head {heads_idx}\")\n",
    "            axes[1, i].matshow(cross_attn_scores[heads_idx], cmap='viridis')\n",
    "            axes[1, i].set_yticks(range(trg_len), trg_words_list)\n",
    "            axes[1, i].set_xticks(range(src_len), src_words_list, rotation=90)\n",
    "            axes[1, i].set_title(f\"head {heads_idx}\")\n",
    "\n",
    "        plt.show()\n",
    "\n",
    "\n",
    "    def __call__(self, sentence_list, heads_list=None, layer_idx=-1):\n",
    "        # 将输入句子列表转换为小写，并使用 MosesTokenizer 进行分词处理。\n",
    "        sentence_list = [\" \".join(self.mose_tokenizer.tokenize(s.lower())) for s in sentence_list]\n",
    "        # 将分词后的结果进行 BPE 编码，得到 tokens_list。\n",
    "        tokens_list = [s.split() for s in self.bpe.apply(sentence_list)]\n",
    "        # 使用 src_tokenizer 对 tokens_list 进行编码，同时添加起始标记 ([BOS]) 和结束标记 ([EOS])。\n",
    "        encoder_input, attn_mask = self.src_tokenizer.encode(\n",
    "            tokens_list,\n",
    "            add_bos=True,\n",
    "            add_eos=True,\n",
    "            return_mask=True,\n",
    "            )\n",
    "        encoder_input = torch.Tensor(encoder_input).to(dtype=torch.int64)\n",
    "        # 使用模型的 infer 方法对编码器输入进行推理，得到输出结果 outputs\n",
    "        outputs = model.infer(encoder_inputs=encoder_input, encoder_inputs_mask=attn_mask)\n",
    "\n",
    "        preds = outputs.preds.numpy()\n",
    "        # 使用目标语言的 trg_tokenizer 对预测序列进行解码，得到解码后的目标语言句子列表 trg_decoded。\n",
    "        trg_decoded = self.trg_tokenizer.decode(preds, split=True, remove_eos=False, remove_bos=False, remove_pad=False)\n",
    "        # 使用源语言的 src_tokenizer 对编码器输入进行解码，得到解码后的源语言句子列表 src_decoded。为下面绘制热力图做准备。\n",
    "        src_decoded = self.src_tokenizer.decode(\n",
    "            encoder_input.numpy(),\n",
    "            split=True,\n",
    "            remove_bos=False,\n",
    "            remove_eos=False\n",
    "            )\n",
    "\n",
    "        # post processed attn scores\n",
    "        # outputs.decoder_attentions[-1]  # the last layer of self-attention scores\n",
    "\n",
    "        # draw the attention map of the last decoder block\n",
    "        for attn_score, cross_attn_score, src, trg in zip(\n",
    "            outputs.decoder_self_attn_scores[layer_idx], outputs.decoder_cross_attn_scores[layer_idx], src_decoded, trg_decoded):\n",
    "            if heads_list is None:# 如果没有指定heads_list，就画单个热力图\n",
    "                self.draw_attention_map(\n",
    "                    attn_score,\n",
    "                    cross_attn_score,\n",
    "                    src,\n",
    "                    trg,\n",
    "                )\n",
    "            else:# 如果指定了heads_list，就画多个热力图\n",
    "                self.draw_attention_maps(\n",
    "                    attn_score,\n",
    "                    cross_attn_score,\n",
    "                    src,\n",
    "                    trg,\n",
    "                    heads_list=heads_list,\n",
    "                    )\n",
    "        return [self.mose_detokenizer.tokenize(self.pattern.sub(\"\", s).split()) for s in self.trg_tokenizer.decode(preds)] #将解码后的目标语言句子列表返回，并使用 mose_detokenizer 进行去标记化，最终得到翻译后的结果。\n",
    "\n",
    "\n",
    "# sentence_list = [\n",
    "#     \"Mann in einem kleinen weißen Boot auf einem See.\",  # Man in a small white boat on a lake.\n",
    "#     \"Ein Mann mit einem Eimer und ein Mädchen mit einem Hut am Strand.\", # A man with a bucket and a girl in a hat on the beach.\n",
    "#     \"Drei Männer auf Pferden während eines Rennens.\",  # Three men on horses during a race.\n",
    "#     \"Ein Mann und eine Frau essen zu Abend\",  # 一个男人和一个女人在吃晚餐\n",
    "# ]\n",
    "sentence_list = [\n",
    "    \"Mann in einem kleinen weißen Boot auf einem See.\",  # Man in a small white boat on a lake.\n",
    "    # \"Ein Mann mit einem Eimer und ein Mädchen mit einem Hut am Strand.\", # A man with a bucket and a girl in a hat on the beach.\n",
    "    # \"Drei Männer auf Pferden während eines Rennens.\",  # Three men on horses during a race.\n",
    "    # \"Ein Mann und eine Frau essen zu Abend\",  # 一个男人和一个女人在吃晚餐\n",
    "]\n",
    "\n",
    "# load checkpoints\n",
    "model = TransformerModel(config)\n",
    "model.load_state_dict(state_dict)\n",
    "translator = Translator(model.cpu(), tokenizer, tokenizer)\n",
    "translator(\n",
    "    sentence_list,\n",
    "    layer_idx=-1,\n",
    "    # heads_list=[0, 1, 2, 3, 4, 5, 6, 7]\n",
    "    )\n"
   ]
  },
  {
   "cell_type": "code",
   "source": [
    "!ls checkpoints"
   ],
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "e0WkUQuUe-Cy",
    "outputId": "433e3d70-4f34-4376-e4a3-1b8834e71f88"
   },
   "execution_count": null,
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "translate-transformer-not-share\n"
     ]
    }
   ]
  },
  {
   "cell_type": "code",
   "source": [
    "# prompt: 把best.ckpt复制到云盘内\n",
    "\n",
    "!cp -r checkpoints/translate-transformer-not-share/best.ckpt /content/drive/MyDrive/transformer-de-en\n"
   ],
   "metadata": {
    "id": "_1ZLtdahywWf"
   },
   "execution_count": null,
   "outputs": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "name": "python3",
   "language": "python",
   "display_name": "Python 3 (ipykernel)"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.8"
  },
  "orig_nbformat": 4,
  "colab": {
   "provenance": [],
   "gpuType": "T4"
  },
  "accelerator": "GPU",
  "widgets": {
   "application/vnd.jupyter.widget-state+json": {
    "55146ac7395840dca847e0f63aa80561": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "HBoxModel",
     "model_module_version": "1.5.0",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HBoxModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HBoxView",
      "box_style": "",
      "children": [
       "IPY_MODEL_abb9bc76c0ce4634bd340be20c074b8c",
       "IPY_MODEL_a89d790df59245fcaf26335d4903c9b4",
       "IPY_MODEL_f837255914194dc792cf1514dee03dc5"
      ],
      "layout": "IPY_MODEL_46a51a1719d8444eb5877720253d3c37"
     }
    },
    "abb9bc76c0ce4634bd340be20c074b8c": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "HTMLModel",
     "model_module_version": "1.5.0",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HTMLModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HTMLView",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_013d2a6b90144432bbfb15136235faba",
      "placeholder": "​",
      "style": "IPY_MODEL_2b82e42c34804b13bc83be4c7009d4e2",
      "value": ""
     }
    },
    "a89d790df59245fcaf26335d4903c9b4": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "FloatProgressModel",
     "model_module_version": "1.5.0",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "FloatProgressModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "ProgressView",
      "bar_style": "success",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_9233439bdd6746c28ad4a20ef47799f6",
      "max": 280,
      "min": 0,
      "orientation": "horizontal",
      "style": "IPY_MODEL_0e10428326bc436e8dbc079e89570bde",
      "value": 280
     }
    },
    "f837255914194dc792cf1514dee03dc5": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "HTMLModel",
     "model_module_version": "1.5.0",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HTMLModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HTMLView",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_0fe4ed7283c04496affe727c235d31c4",
      "placeholder": "​",
      "style": "IPY_MODEL_0c0c7229347b49ffbb9a0f7bd41199b9",
      "value": " 21020/? [21:30&lt;00:00, 15.32it/s, epoch=19, loss=2.61, val_loss=3.41]"
     }
    },
    "46a51a1719d8444eb5877720253d3c37": {
     "model_module": "@jupyter-widgets/base",
     "model_name": "LayoutModel",
     "model_module_version": "1.2.0",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "013d2a6b90144432bbfb15136235faba": {
     "model_module": "@jupyter-widgets/base",
     "model_name": "LayoutModel",
     "model_module_version": "1.2.0",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "2b82e42c34804b13bc83be4c7009d4e2": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "DescriptionStyleModel",
     "model_module_version": "1.5.0",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "DescriptionStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "description_width": ""
     }
    },
    "9233439bdd6746c28ad4a20ef47799f6": {
     "model_module": "@jupyter-widgets/base",
     "model_name": "LayoutModel",
     "model_module_version": "1.2.0",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "0e10428326bc436e8dbc079e89570bde": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "ProgressStyleModel",
     "model_module_version": "1.5.0",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "ProgressStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "bar_color": null,
      "description_width": ""
     }
    },
    "0fe4ed7283c04496affe727c235d31c4": {
     "model_module": "@jupyter-widgets/base",
     "model_name": "LayoutModel",
     "model_module_version": "1.2.0",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "0c0c7229347b49ffbb9a0f7bd41199b9": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "DescriptionStyleModel",
     "model_module_version": "1.5.0",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "DescriptionStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "description_width": ""
     }
    },
    "7190c928edb040c3a523cdd2e3f45572": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "HBoxModel",
     "model_module_version": "1.5.0",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HBoxModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HBoxView",
      "box_style": "",
      "children": [
       "IPY_MODEL_990741ff083d457587665d8f620b69c3",
       "IPY_MODEL_00fe6a550df547cea5b1e0d84c1a3f5f",
       "IPY_MODEL_fab8b1e3187841ee894b92859fa4821b"
      ],
      "layout": "IPY_MODEL_f9b0d916e1a64c2a9f384e42f3d5dcab"
     }
    },
    "990741ff083d457587665d8f620b69c3": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "HTMLModel",
     "model_module_version": "1.5.0",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HTMLModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HTMLView",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_a78199650ecc47bd81f482a2671b563a",
      "placeholder": "​",
      "style": "IPY_MODEL_673bd3773a374261a01cfc48081c27f3",
      "value": "100%"
     }
    },
    "00fe6a550df547cea5b1e0d84c1a3f5f": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "FloatProgressModel",
     "model_module_version": "1.5.0",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "FloatProgressModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "ProgressView",
      "bar_style": "success",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_83f345f7424c43929d7a304cbfb6d0fe",
      "max": 9714,
      "min": 0,
      "orientation": "horizontal",
      "style": "IPY_MODEL_58d69d086f644e89937347e1f9261d6f",
      "value": 9714
     }
    },
    "fab8b1e3187841ee894b92859fa4821b": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "HTMLModel",
     "model_module_version": "1.5.0",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HTMLModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HTMLView",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_8cf462fa996c41b18fb4571e0a757363",
      "placeholder": "​",
      "style": "IPY_MODEL_434ac4c51db74681942d2d3bd869b1df",
      "value": " 9714/9714 [00:00&lt;00:00, 236744.37it/s]"
     }
    },
    "f9b0d916e1a64c2a9f384e42f3d5dcab": {
     "model_module": "@jupyter-widgets/base",
     "model_name": "LayoutModel",
     "model_module_version": "1.2.0",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "a78199650ecc47bd81f482a2671b563a": {
     "model_module": "@jupyter-widgets/base",
     "model_name": "LayoutModel",
     "model_module_version": "1.2.0",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "673bd3773a374261a01cfc48081c27f3": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "DescriptionStyleModel",
     "model_module_version": "1.5.0",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "DescriptionStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "description_width": ""
     }
    },
    "83f345f7424c43929d7a304cbfb6d0fe": {
     "model_module": "@jupyter-widgets/base",
     "model_name": "LayoutModel",
     "model_module_version": "1.2.0",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "58d69d086f644e89937347e1f9261d6f": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "ProgressStyleModel",
     "model_module_version": "1.5.0",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "ProgressStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "bar_color": null,
      "description_width": ""
     }
    },
    "8cf462fa996c41b18fb4571e0a757363": {
     "model_module": "@jupyter-widgets/base",
     "model_name": "LayoutModel",
     "model_module_version": "1.2.0",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "434ac4c51db74681942d2d3bd869b1df": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "DescriptionStyleModel",
     "model_module_version": "1.5.0",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "DescriptionStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "description_width": ""
     }
    },
    "c9db4cd83b7b4f53a0fa93b8c365debd": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "HBoxModel",
     "model_module_version": "1.5.0",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HBoxModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HBoxView",
      "box_style": "",
      "children": [
       "IPY_MODEL_a972aba7913b48c6973ae27bff5b9d1d",
       "IPY_MODEL_22aa774ab39e4fd78b0ff08d430d2b5d",
       "IPY_MODEL_9a01f02fb99b4b81ac487d23bc5daf4a"
      ],
      "layout": "IPY_MODEL_19f846338f6b48c9930b58575641e5b8"
     }
    },
    "a972aba7913b48c6973ae27bff5b9d1d": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "HTMLModel",
     "model_module_version": "1.5.0",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HTMLModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HTMLView",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_7d293204dc1b4d97bb5ee670787c7b7d",
      "placeholder": "​",
      "style": "IPY_MODEL_ea8fa440f320435aa75c9bef75bc3f08",
      "value": ""
     }
    },
    "22aa774ab39e4fd78b0ff08d430d2b5d": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "FloatProgressModel",
     "model_module_version": "1.5.0",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "FloatProgressModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "ProgressView",
      "bar_style": "success",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_4e64bcb87e584beda0408a0aa5a659ae",
      "max": 1,
      "min": 0,
      "orientation": "horizontal",
      "style": "IPY_MODEL_b077d7562d814df5b6d839464dd4122f",
      "value": 1
     }
    },
    "9a01f02fb99b4b81ac487d23bc5daf4a": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "HTMLModel",
     "model_module_version": "1.5.0",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HTMLModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HTMLView",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_5a28babf4e2e4393bdc1a093034885ab",
      "placeholder": "​",
      "style": "IPY_MODEL_be07d518c21149d196c610fd57b1eaec",
      "value": " 957/? [00:18&lt;00:00, 51.31it/s]"
     }
    },
    "19f846338f6b48c9930b58575641e5b8": {
     "model_module": "@jupyter-widgets/base",
     "model_name": "LayoutModel",
     "model_module_version": "1.2.0",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "7d293204dc1b4d97bb5ee670787c7b7d": {
     "model_module": "@jupyter-widgets/base",
     "model_name": "LayoutModel",
     "model_module_version": "1.2.0",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "ea8fa440f320435aa75c9bef75bc3f08": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "DescriptionStyleModel",
     "model_module_version": "1.5.0",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "DescriptionStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "description_width": ""
     }
    },
    "4e64bcb87e584beda0408a0aa5a659ae": {
     "model_module": "@jupyter-widgets/base",
     "model_name": "LayoutModel",
     "model_module_version": "1.2.0",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": "20px"
     }
    },
    "b077d7562d814df5b6d839464dd4122f": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "ProgressStyleModel",
     "model_module_version": "1.5.0",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "ProgressStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "bar_color": null,
      "description_width": ""
     }
    },
    "5a28babf4e2e4393bdc1a093034885ab": {
     "model_module": "@jupyter-widgets/base",
     "model_name": "LayoutModel",
     "model_module_version": "1.2.0",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "be07d518c21149d196c610fd57b1eaec": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "DescriptionStyleModel",
     "model_module_version": "1.5.0",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "DescriptionStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "description_width": ""
     }
    },
    "40f7e3754ad44b33acfe0a80b3648a3a": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "HBoxModel",
     "model_module_version": "1.5.0",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HBoxModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HBoxView",
      "box_style": "",
      "children": [
       "IPY_MODEL_b1e51beac50f4947a9dd235d8aa87603",
       "IPY_MODEL_8cd9e9702e114ebc856f56975544ede8",
       "IPY_MODEL_b7c7a718a8654956947108969557ca83"
      ],
      "layout": "IPY_MODEL_20a27d1ec76f4d85b1ffe99401fbb5b7"
     }
    },
    "b1e51beac50f4947a9dd235d8aa87603": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "HTMLModel",
     "model_module_version": "1.5.0",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HTMLModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HTMLView",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_e0ddf3970b3e4248bc87d4649fa9c448",
      "placeholder": "​",
      "style": "IPY_MODEL_d7bdde54e2534c49a207540bd258d3ae",
      "value": "  9%"
     }
    },
    "8cd9e9702e114ebc856f56975544ede8": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "FloatProgressModel",
     "model_module_version": "1.5.0",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "FloatProgressModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "ProgressView",
      "bar_style": "danger",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_22484000400842f0b6e245dc610acbba",
      "max": 128,
      "min": 0,
      "orientation": "horizontal",
      "style": "IPY_MODEL_a66a5b4ff37d4dafa4ba3081aa1359f4",
      "value": 12
     }
    },
    "b7c7a718a8654956947108969557ca83": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "HTMLModel",
     "model_module_version": "1.5.0",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HTMLModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HTMLView",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_0b7866c29e5f4afe9b92de15f1b88c3e",
      "placeholder": "​",
      "style": "IPY_MODEL_333e84a304184c57af1821620ae80f6a",
      "value": " 12/128 [00:00&lt;00:01, 73.96it/s]"
     }
    },
    "20a27d1ec76f4d85b1ffe99401fbb5b7": {
     "model_module": "@jupyter-widgets/base",
     "model_name": "LayoutModel",
     "model_module_version": "1.2.0",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "e0ddf3970b3e4248bc87d4649fa9c448": {
     "model_module": "@jupyter-widgets/base",
     "model_name": "LayoutModel",
     "model_module_version": "1.2.0",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "d7bdde54e2534c49a207540bd258d3ae": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "DescriptionStyleModel",
     "model_module_version": "1.5.0",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "DescriptionStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "description_width": ""
     }
    },
    "22484000400842f0b6e245dc610acbba": {
     "model_module": "@jupyter-widgets/base",
     "model_name": "LayoutModel",
     "model_module_version": "1.2.0",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "a66a5b4ff37d4dafa4ba3081aa1359f4": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "ProgressStyleModel",
     "model_module_version": "1.5.0",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "ProgressStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "bar_color": null,
      "description_width": ""
     }
    },
    "0b7866c29e5f4afe9b92de15f1b88c3e": {
     "model_module": "@jupyter-widgets/base",
     "model_name": "LayoutModel",
     "model_module_version": "1.2.0",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "333e84a304184c57af1821620ae80f6a": {
     "model_module": "@jupyter-widgets/controls",
     "model_name": "DescriptionStyleModel",
     "model_module_version": "1.5.0",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "DescriptionStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "description_width": ""
     }
    }
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
